﻿SET FOREIGN_KEY_CHECKS = 0;

DROP TABLE IF EXISTS  `files`;
CREATE TABLE `files` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `filename` varchar(50) DEFAULT NULL COMMENT '文件名',
  `filepath` varchar(300) DEFAULT NULL COMMENT '文件路径',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=90 DEFAULT CHARSET=utf8;

insert into `files`(`id`,`filename`,`filepath`) values
('69','20170427149327672759019837a09bc.jpg','20170427/149327686751820170427149327672759019837a09bc.jpg'),
('61','googleplus.png','20170421/1492769344955googleplus.png'),
('62','aec379310a55b3190c0aa4a742a98226cefc1774.jpg','20170426/1493208109502aec379310a55b3190c0aa4a742a98226cefc1774.jpg'),
('63','下载.jpg','20170426/1493208427377xiazai.jpg'),
('68','20170427149327672759019837a09bc.jpg','20170427/149327685490820170427149327672759019837a09bc.jpg'),
('70','2017042714932769875901993b45051.jpg','20170427/14932770077372017042714932769875901993b45051.jpg'),
('71','timg.jpg','20170428/1493310283010timg.jpg'),
('72','timg.jpg','20170428/1493387392531timg.jpg'),
('74','timg.jpg','20170428/1493392580929timg.jpg'),
('75','timg01.jpg','20170428/1493393959042timg01.jpg'),
('76','timg (1).jpg','20170428/1493394053041timg (1).jpg'),
('86','20170606.jpg','20170606/149673926527420170606.jpg'),
('85','20170605.jpg','20170605/149665356251520170605.jpg'),
('80','6628.jpg','20170503/14937975116636628.jpg'),
('83','timg.jpg','20170520/1495248844675timg.jpg'),
('89','20170607.jpg','20170607/149682198284720170607.jpg');
DROP TABLE IF EXISTS  `sys_dictionary_data`;
CREATE TABLE `sys_dictionary_data` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(255) DEFAULT NULL COMMENT '名称',
  `value` varchar(255) DEFAULT NULL COMMENT '值',
  `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  `dictionary_type_id` int(11) DEFAULT NULL COMMENT '类型id',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8;

insert into `sys_dictionary_data`(`id`,`name`,`value`,`remark`,`dictionary_type_id`) values
('2','ACCESS_KEY','bRy7xxw8_5gbNoTgAIEQuD9-sOyd0dLRUriP5XnD','','1'),
('3','SECRET_KEY','3vqOy_ppKLHslgEKITv1WKXAsg-e5boN4jUIYgjV','','1'),
('4','bucketname','hmyuan','要上传的空间','1'),
('5','domainName','http://oqjrtyl2q.bkt.clouddn.com','域名','1'),
('6','fileConfig','qcloud','文件存储-
腾讯云：qcloud
七牛：qiniu
本地：local','4'),
('7','region','sh','华南园区：gz； 华北园区：tj；华东园区：sh','3'),
('8','bucketName','hmyuan','','3'),
('9','secretKey','xg9NN7cvzoOindDYdU5RXO0MTL0QbXEg','测试用：PjtFavFb0d9ED6qVJxCJEevDWqeNnALK','3'),
('10','secretId','AKIDCE2bu2zb1B6nEQscOvCF3cw1qQkpJFaf','测试用：AKIDyqW3UaLiW8aprYBYkcOyrdFfuxpUvCFA','3'),
('11','appId','1253876537','测试用：1251204848','3'),
('12','domainName','https://hmyuan-1253876537.cossh.myqcloud.com','测试用：https://hmyuan-1251204848.cossh.myqcloud.com','3'),
('13','domainName','https://hmyuan.com','文件请求域名','2');
DROP TABLE IF EXISTS  `friendurl`;
CREATE TABLE `friendurl` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL COMMENT '名字',
  `url` varchar(300) DEFAULT NULL COMMENT '链接',
  `ordernum` int(11) DEFAULT NULL COMMENT '显示顺序',
  `status` int(11) DEFAULT NULL COMMENT '状态',
  `remark` varchar(500) DEFAULT NULL COMMENT '描述',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS  `tag`;
CREATE TABLE `tag` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL COMMENT '名称',
  `useraccount` varchar(20) DEFAULT NULL COMMENT '创建人账号',
  `createtime` datetime DEFAULT NULL COMMENT '创建日期',
  `status` int(11) DEFAULT NULL COMMENT '状态',
  `usenum` int(11) DEFAULT NULL COMMENT '使用热度',
  `ordernum` int(11) DEFAULT NULL COMMENT '排序序号',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;

insert into `tag`(`id`,`name`,`useraccount`,`createtime`,`status`,`usenum`,`ordernum`) values
('13','服务器','admin','2017-04-28 00:25:44','0','0','0'),
('12','文件操作','admin','2017-04-26 20:09:00','0','0','0'),
('11','mysql','admin','2017-04-24 15:33:15','0','0','0'),
('10','sql','admin','2017-04-21 14:25:43','0','0','0'),
('9','oracle','admin','2017-04-21 11:00:14','0','0','0'),
('14','中文乱码','admin','2017-04-28 23:16:26','0','0','0'),
('15','session','admin','2017-05-03 16:05:56','0','0','0'),
('16','事务控制','admin','2017-06-05 17:06:08','0','0','0'),
('17','自定义注解','admin','2017-06-06 16:54:34','0','0','0'),
('18','图片处理','admin','2017-06-07 15:53:10','0','0','0'),
('19','编译','admin','2017-06-21 20:29:27','0','0','0'),
('20','破解','admin','2017-06-22 13:56:44','0','0','0'),
('21','重定向','admin','2017-06-22 21:32:16','0','0','0'),
('22','公共库','admin','2017-06-28 10:10:23','0','0','0'),
('23','jquery','admin','2017-06-29 12:43:45','0','0','0'),
('24','设计模式','admin','2017-07-11 16:29:37','0','0','0'),
('25','番羽墙','admin','2017-07-17 13:58:38','0','0','0'),
('26','优化','admin','2017-09-06 13:23:29','0','0','0');
DROP TABLE IF EXISTS  `sys_role`;
CREATE TABLE `sys_role` (
  `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `state` varchar(3) COLLATE utf8_unicode_ci DEFAULT '0' COMMENT '状态0:正常 1:禁用 ',
  `name` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '角色名称',
  `roleKey` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '角色标识',
  `description` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '角色描述',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

insert into `sys_role`(`id`,`state`,`name`,`roleKey`,`description`) values
('1','0','系统管理员',null,'系统管理员');
DROP TABLE IF EXISTS  `sys_res_user`;
CREATE TABLE `sys_res_user` (
  `resId` int(11) NOT NULL COMMENT '资源id',
  `userId` int(11) NOT NULL COMMENT '用户id',
  PRIMARY KEY (`userId`,`resId`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

insert into `sys_res_user`(`resId`,`userId`) values
('1','2'),
('2','2'),
('3','2'),
('5','2'),
('6','2'),
('7','2'),
('8','2'),
('9','2'),
('10','2'),
('13','2'),
('14','2');
DROP TABLE IF EXISTS  `sys_user_role`;
CREATE TABLE `sys_user_role` (
  `userId` int(11) NOT NULL COMMENT '用户id',
  `roleId` int(11) NOT NULL COMMENT '角色id',
  PRIMARY KEY (`userId`,`roleId`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

insert into `sys_user_role`(`userId`,`roleId`) values
('2','1');
DROP TABLE IF EXISTS  `sys_resources`;
CREATE TABLE `sys_resources` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '资源名称',
  `parentId` int(11) DEFAULT NULL COMMENT '父id',
  `resKey` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '资源标识',
  `type` varchar(40) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '类型',
  `resUrl` varchar(200) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '资源路径',
  `level` int(4) DEFAULT NULL COMMENT '所属层次',
  `icon` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '资源图标',
  `ishide` int(3) DEFAULT '0' COMMENT '是否隐藏0显示1隐藏',
  `description` varchar(500) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '资源描述',
  `orderNum` int(4) DEFAULT '0' COMMENT '排序序号',
  `isdelete` int(4) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=15 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

insert into `sys_resources`(`id`,`name`,`parentId`,`resKey`,`type`,`resUrl`,`level`,`icon`,`ishide`,`description`,`orderNum`,`isdelete`) values
('1','系统管理','0','sys',null,'','1','','0','系统管理','1','0'),
('2','用户管理','1','sysuser',null,'/back/sysuser/sysuserPage','2','&#xe613;','0','用户管理','1','0'),
('3','角色管理','1','sysrole',null,'/back/sysrole/sysrolePage','2','&#xe633;','0','角色管理','2','0'),
('4','菜单资源管理','1','sysresources',null,'/back/sysresources/sysresourcesPage','2','&#xe649;','1','菜单资源管理','3','0'),
('5','博客管理','0','blog',null,'','1','','0','博客管理','0','0'),
('6','我的文章','5','article',null,'/back/article/articlePage','2','','0','我的博客','1','0'),
('7','讨论留言','5','comment',null,'/back/comment/commentPage','2','','0','讨论留言','2','0'),
('8','博客类别','5','category',null,'/back/category/categoryPage','2','','0','博客类别','3','0'),
('9','标签管理','5','tag',null,'/back/tag/tagPage','2','','0','标签管理','4','0'),
('10','页面管理','5','single',null,'/back/single/singlePage','2','','0','页面管理','6','0'),
('11','友情链接','5','friendurl',null,'/back/friendurl/friendurlPage','2','','1','友情链接','5','0'),
('13','文件管理','5','files',null,'/back/files/filesPage','2','','0','文件管理','7','0'),
('14','字典管理','1','dictionary',null,'/back/dictionary/dictionaryTypePage','2','','0','字典管理，管理系统配置','0','0');
DROP TABLE IF EXISTS  `article_tag`;
CREATE TABLE `article_tag` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `articleid` int(11) DEFAULT NULL COMMENT '文章id',
  `tagid` int(11) DEFAULT NULL COMMENT '标签id',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=312 DEFAULT CHARSET=utf8;

insert into `article_tag`(`id`,`articleid`,`tagid`) values
('267','41','9'),
('265','42','9'),
('264','42','10'),
('266','41','10'),
('263','42','11'),
('262','43','12'),
('293','44','13'),
('260','45','12'),
('259','45','13'),
('258','46','13'),
('257','46','14'),
('256','48','13'),
('255','48','15'),
('254','49','13'),
('253','50','16'),
('252','51','17'),
('251','52','12'),
('250','52','18'),
('268','53','19'),
('271','54','20'),
('289','55','13'),
('288','55','21'),
('281','56','10'),
('280','56','16'),
('290','57','22'),
('291','58','23'),
('292','59','23'),
('305','60','24'),
('298','61','25'),
('302','62','19'),
('301','62','24'),
('304','63','20'),
('311','64','10'),
('310','64','11'),
('309','64','26');
DROP TABLE IF EXISTS  `category`;
CREATE TABLE `category` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL COMMENT '类别名称',
  `createtime` datetime DEFAULT NULL COMMENT '创建日期',
  `parentid` int(11) DEFAULT NULL COMMENT '父id',
  `status` int(11) DEFAULT NULL COMMENT '状态',
  `useraccount` varchar(20) DEFAULT NULL COMMENT '创建人账号',
  `ordernum` int(11) DEFAULT NULL COMMENT '排序序号',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;

insert into `category`(`id`,`name`,`createtime`,`parentid`,`status`,`useraccount`,`ordernum`) values
('4','数据库','2017-04-21 10:39:46',null,'0','admin','0'),
('5','其他','2017-04-26 20:00:16',null,'0','admin','6'),
('6','服务器','2017-04-28 00:26:17',null,'0','admin','0'),
('7','java','2017-06-05 16:09:06',null,'0','admin','0'),
('8','前端','2017-06-28 09:35:16',null,'0','admin','5');
DROP TABLE IF EXISTS  `article`;
CREATE TABLE `article` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `userid` int(11) DEFAULT NULL COMMENT '用户id',
  `content` longtext COMMENT '内容',
  `createtime` timestamp NULL DEFAULT NULL COMMENT ' 创建时间',
  `clicknum` int(11) DEFAULT NULL COMMENT '点击量',
  `status` int(11) DEFAULT NULL COMMENT '状态0正常1隐藏2加密显示',
  `password` varchar(50) DEFAULT NULL,
  `type` int(11) DEFAULT NULL COMMENT '文章类型',
  `topimg` varchar(300) DEFAULT NULL COMMENT '顶部配图',
  `summary` varchar(200) DEFAULT NULL COMMENT '摘要',
  `useraccount` varchar(20) DEFAULT NULL COMMENT '创建人账号',
  `title` varchar(100) DEFAULT NULL COMMENT '文章标题',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=65 DEFAULT CHARSET=utf8;

insert into `article`(`id`,`userid`,`content`,`createtime`,`clicknum`,`status`,`password`,`type`,`topimg`,`summary`,`useraccount`,`title`) values
('41','2','#问题：
做开发这么久了这些sql的细节还是没记住，今天在我自己网站上也记录一下！
查询数据库中字段为null的数据时，想当然的就使用等号来判断(rowname = null 或 rowname = \'\')，可是执行了之后才发现字段为null的值根本查不出来！
#解决办法：
我承认我sql水平比较差，最后上网查了一下，改用is null果然可以了！
查询字段为空数据的sql:
```sql
select * from tablename t where t.rowname is null;
```
查询字段为不空数据的sql:
```sql
select * from tablename t where t.rowname is not null;
```

#总结：
数据库sql查询的语法并不难，主要是一些细节问题，遇到了一次以后就要记住。:tw-1f605:加油！:tw-1f624:','2017-04-21 11:00:14','64','0','','1','~~fileDomainName~~//img/201706/1497513132837.jpg','问题：做开发这么久了这些sql的细节还是没记住，今天在我自己网站上也记录一下！查询数据库中字段为null的数据时，想当然的就使用等号来判断(rowname = null 或 rowname = ‘’)，可是执行了之后才发现字段为null的值根本查不出来！
解决办法：我承认我sql水平比较差，最后上网查了一下，改用is null果然可以了！查询字段为空数据的sql:select ...','admin','oracle数据查询字段为空的数据'),
('42','2','#业务需求：
当前有一个文章列表按照时间排序，点击一条查看详情时，详情页面要显示当前文章的前一条和后一条数据。
由于功能简单，两条数据有共通的地方，想用一条sql查出两条数据，添加一个orderposition标识前一条(front)、后一条（back）!
##功能实现sql（Oracle）：
```sql
with t as (
	select t.,rownum as rn from (
		select from tablename t
		where 1=1 —这里写查询条件
		order by t.createtime desc
	) t
)
select t.*,\'back\' as orderposition from t where t.rn=(select t.rn+1 from t where t.id = #{当前文章的id})
union all
select t.*,\'front\' as orderposition from t where t.rn=(select t.rn-1 from t where t.id = #{当前文章的id})
```
##功能实现sql（Mysql）：
```sql
(select a.*,\'front\' orderposition from article a where edit_date >= (select edit_date from article where id = 15) order by a.edit_date ,id desc limit 1,1 )
union all
(select a.*,\'back\' orderposition from article a where edit_date <= (select edit_date from article where id = 15) order by a.edit_date desc,id limit 1,1);
```
#总结：
也没什么总结的，就这样了，好好学习技术，成为大牛！','2017-04-21 14:25:43','136','0','','1','~~fileDomainName~~//img/201706/1497512880988.jpg','业务需求：当前有一个文章列表按照时间排序，点击一条查看详情时，详情页面要显示当前文章的前一条和后一条数据。由于功能简单，两条数据有共通的地方，想用一条sql查出两条数据，添加一个orderposition标识前一条(front)、后一条（back）!
功能实现sql（Oracle）：with t as (    select t.,rownum as rn from (    ...','admin','数据库查询上一条和下一条数据sql'),
('43','2','#问题：
在使用Windows系统删除文件或者文件夹的时候，有时会出现“找不到该项目”的错误提示，再次删除还是不行。
![](~~fileDomainName~~/img/201706/1497512720497.jpg)
#解决办法：
##1.新建一个文本文档。
打开，在文本中输入：

	DEL /F /A /Q \\?\\%1
	RD /S /Q \\?\\%1
![](~~fileDomainName~~/img/201706/1497512744719.jpg)
##2.保存
另存为“删除文件.bat”（或者保存再重命名）
##3.执行
将我们要删除的文件夹拉到“删除文件.bat”这个文件的图标上，松开鼠标。会发现屏幕稍微卡顿了一下，然后，那个删不掉的文件夹就不见了！','2017-04-26 20:09:00','104','0','','1','~~fileDomainName~~//img/201706/1497512696106.jpg','问题：在使用Windows系统删除文件或者文件夹的时候，有时会出现“找不到该项目”的错误提示，再次删除还是不行。
解决办法：1.新建一个文本文档。打开，在文本中输入：
DEL /F /A /Q \\?\\%1RD /S /Q \\?\\%1
2.保存另存为“删除文件.bat”（或者保存再重命名）
3.执行将我们要删除的文件夹拉到“删除文件.bat”这个文件的图标上，松开鼠标。会发现屏幕...','admin','Windows删除文件夹提示找不到项目'),
('46','2','#问题：
使用tomcat启动web工程，url传参带有中文，java中获取到中文乱码。
检查web工程中字符集过滤都已经设置好了，但是url中传的参数仍然乱码。
#解决办法：
##修改tomcat配置文件
打开tomcat的server.xml，
找到

	<Connector acceptCount="100" connectionTimeout="20000" disableUploadTimeout="true" port="80" redirectPort="8443">  
并在最后加上**useBodyEncodingForURI="true" URIEncoding="UTF-8"**，如下

	<Connector acceptCount="100" connectionTimeout="20000" disableUploadTimeout="true" port="80" redirectPort="8443"  useBodyEncodingForURI="true" URIEncoding="UTF-8">  
##重启tomcat：
问题解决','2017-04-28 23:16:26','110','0','','1','~~fileDomainName~~//img/201706/1497512071330.jpeg','问题：使用tomcat启动web工程，url传参带有中文，java中获取到中文乱码。检查web工程中字符集过滤都已经设置好了，但是url中传的参数仍然乱码。
解决办法：修改tomcat配置文件打开tomcat的server.xml，找到
<Connector acceptCount="100" connectionTimeout="20000" disableUploadTim...','admin','tomcat字符集设置 url中文乱码解决'),
('44','2','#问题描述：
**随着网络安全形势的发展，SSL已是各大网站的标配，免费的SSL证书中，首推就是Let\'s Encrypt。**
#解决方案：
##1.证书生成与下载参考：
    http://www.boxfun.net/2017/02/18/apply-free-ssl-ca-win7-powershell-letsencrypt/
    http://blog.csdn.net/i348018533/article/details/50788703
##2.Apache导入证书：
###2.1文件列表：
	HMYUAN.crt 
	HMYUAN.crt.pem 
	HMYUAN.csr.pem 
	HMYUAN.key.pem 
	HMYUAN.pfx
	HMYUAN-issuer.crt 
	HMYUAN-issuer.crt.pem
###2.2将HMYUAN-issuer.crt.pem合并到HMYUAN.crt.pem中，得到一个新文件：HMYUAN-fullchain.pem
###2.3HMYUAN-fullchain.pem的内容如下：
	-----BEGIN CERTIFICATE-----
	MIIE+DCCA+CgAwIBAgISA0cXr6maZ2kultSItOmsri9TMA0GCSqGSIb3DQEBCwUA
	MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
	ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNzA0MjcxMzE5MDBaFw0x
	NzA3MjYxMzE5MDBaMBUxEzARBgNVBAMTCmhteXVhbi5jb20wggEiMA0GCSqGSIb3
	DQEBAQUAA4IBDwAwggEKAoIBAQCvNoaLPQg++Jgmsl9V5MsXRRH/dmdNv738j1I5
	ETwF9Cl6lECg5vwQCopLdaiP2Y4+0F9V8cZLhxPZPv2pEaXFl18ZJYzKD6HQ8IOj
	OPL4IOXsmrYlli4Aws4Pyro8N2bgzbA/Fnvpr88qo4F9gPMgyDRj+NzxxeXhtNtm
	nvGPgiXe6Pwk12ppxCRpZMBSFAkX9ZidkXfHIEEdIjKAS6+nxN6b5Y10kNQzNN8c
	zKvZSgej3LzDQ63NJ/szAHDQBFp9X2Xqmpi8wzJHzOBdUErJgLIKtxlFsSXHgOef
	8vz1vq/YUy8mibJGTNAYlob6bWhrhSgv4TrjQRQKSGVJDZWFAgMBAAGjggILMIIC
	BzAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
	MAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFPnci6ra820NNTE2W4LvnkzB7sXAMB8G
	A1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMHAGCCsGAQUFBwEBBGQwYjAv
	BggrBgEFBQcwAYYjaHR0cDovL29jc3AuaW50LXgzLmxldHNlbmNyeXB0Lm9yZy8w
	LwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlwdC5vcmcv
	MBUGA1UdEQQOMAyCCmhteXVhbi5jb20wgf4GA1UdIASB9jCB8zAIBgZngQwBAgEw
	geYGCysGAQQBgt8TAQEBMIHWMCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxldHNl
	bmNyeXB0Lm9yZzCBqwYIKwYBBQUHAgIwgZ4MgZtUaGlzIENlcnRpZmljYXRlIG1h
	eSBvbmx5IGJlIHJlbGllZCB1cG9uIGJ5IFJlbHlpbmcgUGFydGllcyBhbmQgb25s
	eSBpbiBhY2NvcmRhbmNlIHdpdGggdGhlIENlcnRpZmljYXRlIFBvbGljeSBmb3Vu
	ZCBhdCBodHRwczovL2xldHNlbmNyeXB0Lm9yZy9yZXBvc2l0b3J5LzANBgkqhkiG
	9w0BAQsFAAOCAQEAZkuvjg6zr+tSAGFWQZG2/jK9Im4kS1swxcfHJqeMCIvNCpP8
	3tmCfqF/SNBW5Z2EYbAOa6ZuNM4DSl8NmhNOxewxDuhvD1kz+W7GAlw6KXXCA0Vl
	Rc3BoUpWa74ANznpmyKjVZpIASPu1gWFRJ7dDyeZLgUwhj+GZdo2Fxy3xt53Il49
	mpraX/1GOMF4oS8FmjMqR35A41Ll2ZaMyqBAsZFn93HU6B4fGq0IVo9SNct+UMRo
	8+/qB5IkTaJo7lyFQhkGs8rJKkez1/E2gtPWO2KqwJTrH5Cr/ywiD1kPMl40B03Q
	6RjQ5BtGBxM1LIbIgq2YvhdZcpOz2aDct38IOg==
	-----END CERTIFICATE-----
	-----BEGIN CERTIFICATE-----
	MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
	MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
	DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
	SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
	GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
	AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
	q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
	SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
	Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
	a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
	/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
	AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
	CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
	bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
	c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
	VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
	ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
	MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
	Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
	AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
	uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
	wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
	X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
	PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
	KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
	-----END CERTIFICATE-----
###2.4httpd-vhosts.conf中的配置：
```xml
<VirtualHost *:443>   
	ServerName hmyuan.com   
	ProxyIOBufferSize 8192  
	ProxyRequests Off   
	ProxyVia Full   
	SSLEngine on
	SSLProxyEngine on
	SSLCertificateFile /ACMECertificate/HMYUAN-fullchain.pem
	SSLCertificateKeyFile /ACMECertificate/HMYUAN.key.pem
	ProxyReqUESTS oFF
	ProxyPass / http://hmyuan.com:8180/ smax=5 max=20 ttl=120 retry=300   
</VirtualHost>  
```

------------


------------


#申请免费的通配符证书\\泛域名证书
参考：https://moeclub.org/2017/05/05/169/
申请通配符证书:
假设你已经能够使用admin@你的域名接收邮件.
打开Linux系统的终端,默认你已经安装openssl.
输入以下命令:
将命令中的domain.ltd替换为你的域名.
```shell
openssl req -new -newkey rsa:2048 -nodes -out domain.csr -keyout domain.key.pem -subj "/C=CN/ST=00/L=/O=/CN=*.domain.ltd"
```
打开domain.csr文件并复制内容.
```shell
cat domain.csr
```
打开免费的通配符证书申请网页:
第一个框框内粘贴刚刚复制的内容.
第二个框框内填写邮箱admin@你的域名.
最后三个框框不用管,点击 Verify .
确认并选择你的邮箱.
接受并确认邮件.
接受包含证书的邮件.
补完证书链.
将以下内容粘贴至证书文件的最后面.
```shell
-----BEGIN CERTIFICATE-----
MIIETTCCAzWgAwIBAgILBAAAAAABRE7wNjEwDQYJKoZIhvcNAQELBQAwVzELMAkG
.
.
.
MTh89N1SyvNTBCVXVmaU6Avu5gMUTu79bZRknl7OedSyps9AsUSoPocZXun4IRZZ
Uw==
-----END CERTIFICATE-----
```
打包保存csr文件,密钥文件,证书文件.
配置SSL证书,并检测有效性.','2017-04-28 00:25:44','89','0','','1','~~fileDomainName~~//img/201706/1497512488898.jpg','问题描述：随着网络安全形势的发展，SSL已是各大网站的标配，免费的SSL证书中，首推就是Let’s Encrypt。
解决方案：1.证书生成与下载参考：http://www.boxfun.net/2017/02/18/apply-free-ssl-ca-win7-powershell-letsencrypt/http://blog.csdn.net/i348018533/art...','admin','申请免费的SSL证书（Windows，PowerShell，Let’s Encrypt）'),
('45','2','#问题：
HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术。大流量的WEB站点常常使用GZIP压缩技术来让用户感受更快的速度。
#解决方法：
##第一步：编辑 http.conf 文件
去掉 #LoadModule headers_module modules/mod_headers.so 前面的注释#
去掉 #LoadModule deflate_module modules/mod_deflate.so 前面的注释#
去掉 #LoadModule filter_module modules/mod_filter.so 前面的注释# 
##第二步：文件末尾加上
```xml
<IfModule deflate_module>
	SetOutputFilter DEFLATE
	# Don’t compress images and other 
	SetEnvIfNoCase Request_URI .(?:gif|jpe?g|png)$ no-gzip dont-vary 
	SetEnvIfNoCase Request_URI .(?:exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary 
	SetEnvIfNoCase Request_URI .(?:pdf|doc)$ no-gzip dont-vary 
	AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css 
	AddOutputFilterByType DEFLATE application/x-javascript
</IfModule>
```
##第三步：重启Apache

#备注：
实际操作中**第一步**只去掉前两个的注释再Apache2.4中可能启动不了
但是Apache2.2中可以正常启动，
不知道是不是我其他那些地方配置影响到了，
还好最后去掉第三个#LoadModule filter_module modules/mod_filter.so的注释后Apache2.4中的问题解决了','2017-04-28 21:54:33','71','0','','1','~~fileDomainName~~//img/201706/1497512187017.jpg','问题：HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术。大流量的WEB站点常常使用GZIP压缩技术来让用户感受更快的速度。
解决方法：1.编辑 http.conf 文件去掉 #LoadModule headers_module modules/mod_headers.so 前面的注释#去掉 #LoadModule deflate_module modules/...','admin','Apache2.4开启GZIP功能'),
('37','2','###本人原创！
**网站建设过程中用到了目前比较流行的UI框架和后台框架。
前台页面布局模仿googleplus：https://plus.google.com/explore
兼容：IE10+，chrome，火狐**
源码地址：http://git.oschina.net/suxiaofei/hmyuanblog
![](~~fileDomainName~~/img/201706/1497520723607.png)
#前端UI:
##前台UI：material design lite

UI官网：https://www.getmdl.io
UI中文官网：https://www.getmdl.com.cn

##前台图标：material design icon
图标官网：http://google.github.io/material-design-icons/
图标库：https://www.google.com/design/icons/
##前台同步加载进度条：pace.min.js
同步加载进度条官网：http://github.hubspot.com/pace/
##后台UI：layUI
UI官网：https://www.layui.com/
##后台富文本编辑器
Editor.md：https://pandao.github.io/editor.md/
#技术框架：
spring
springMVC
mybatis
mybatis分页插件-PageHelper
插件网址：https://github.com/pagehelper/Mybatis-PageHelper
#运行环境：
MySql数据库
JDK1.7
tomcat8
服务器Apache代理','2017-04-10 09:32:49','454','2','about','100','~~fileDomainName~~//img/201706/1497520461756.jpg','E886','admin','关于'),
('64','2','#前言
刚进入一个互联网公司，公司数据库用的时MySQL，部门老大发现线上环境某个分页列表查询需要20多秒，我正好要熟悉业务，就把这部分优化工作交给了我。
#优化过程
##1.第一步，避免不必要的连表查询

我先查看了源码，找到了查询列表时要执行的sql，一条查询总数的count，另一条查询当前页数据，放到数据库执行了一下每条sql执行时间12秒左右。
又看了sql关联的几张表，数据量最大的一张有600多万条数据，该加的索引都已经加了。
**初步分析**：是由于数据量大，再加上表的连接查询，导致了查询速度慢。
**解决方法**：将没有影响到where条件判断的关联表拆除，java代码中获取到第一次查询表的关联字段，再使用in（，，）条件查询，查出被去除表的数据，整合到第一次查询的结果中。
**优化结果**：执行时间2.5s左右，这样优化后一共有三条sql（查询count 2.4s,查询列表 0.1s,被去除表查询0.1s）
##2.第二步，减少统计count时扫描数据的数量
经过第一步的优化已经快了很多了，但是查询count要浪费掉那么多的时间，心里感觉还是不爽。
**初步分析**：数据库时引擎是innodb，使用EXPLAIN分析sql执行，发现count查询时会把整张表中的数据都扫描一遍，于是想到能不能不要扫描整张表，但从数据库优化方面我已经想不到什么方法了。
**解决方法**：数据量大的时候查询count耗时太多，建议条数大于10000时，分页显示总数>10000,只允许查询前1000页数据，具体的查询通过检索条件来限定
```sql
SELECT
	count(0)
FROM
	(
		SELECT
			a.id
		FROM
			table1 a
		LEFT JOIN table2 b ON a.credit_id = b.id
		LEFT JOIN table3 og ON b.group_id = og.id
		LEFT JOIN table4 og2 ON og.parent_id = og2.id
		WHERE
			a.relationship = 1
		LIMIT 10000
	) aa
```
**优化结果**：这样优化完查询count时间降低到了0.2s(增加一个查询条件（AND a.amount_guaranteed <> 1）后 0.5s)，结果还是比较理想的。
**无意中发现某宝购物网站也是这么做的**，下图所示
![](~~fileDomainName~~/img/201709/1504675944797.png)
#总结
这样优化完，检索时间就从原来的20多秒降低到了1s以内，感觉还是比较理想的。

另外，统计前一万条的业务还没给老大确认，应该没问题，只是显示列表用的bootstrap-table封装好的自动列表数据，对于显示（总数>10000）不知道好不好处理。','2017-09-06 13:23:28','24','0','','1','~~fileDomainName~~//img/201709/1504675402878.jpg','前言刚进入一个互联网公司，公司数据库用的时MySQL，部门老大发现线上环境某个分页列表查询需要20多秒，我正好要熟悉业务，就把这部分优化工作交给了我。
优化过程1.第一步，避免不必要的连表查询我先查看了源码，找到了查询列表时要执行的sql，一条查询总数的count，另一条查询当前页数据，放到数据库执行了一下每条sql执行时间12秒左右。又看了sql关联的几张表，数据量最大的一张...','admin','sql优化过程记录（MySQL）'),
('48','2','##问题：
使用Apache代理tomcat时，遇到session丢失导致网站不能登录
#问题分析：
通过Apache代理之后，tomcat工程原来的访问路径（https://o.o.hmyuan.com/hmyuan/ ）改变为（https://o.o.hmyuan.com ）
导致sessionid找不到，只要在Apache里做好相应的路径映射就可以解决问题了
#解决方法：
####修改Apache配置文件

	ProxyPass /o_o_hmyuan_com/ !
    ProxyPass / ajp://o.o.hmyuan.com:8009/o_o_hmyuan_com/
    ProxyPassReverse / ajp://o.o.hmyuan.com:8009/o_o_hmyuan_com/
    ExtFilterDefine fixtext mode=output intype=text/html cmd="/bin/sed \'s,/o_o_hmyuan_com,,g\'"
    SetOutputFilter fixtext
####添加如下配置
	#此处项目名称 /o_o_hmyuan_com/ 代理为 / 跟目录访问，session会丢失，需要配置如下信息
	ProxyPassReversecookiePath /o_o_hmyuan_com /

其中“ProxyPassReversecookiePath”的两个参数“/o_o_hmyuan_com”表示被代理的路径；“/”表示经过代理之后的路径
####修改之后

	ProxyPass /o_o_hmyuan_com/ !
    ProxyPass / ajp://o.o.hmyuan.com:8009/o_o_hmyuan_com/
    ProxyPassReverse / ajp://o.o.hmyuan.com:8009/o_o_hmyuan_com/
	ProxyPassReversecookiePath /o_o_hmyuan_com /
    ExtFilterDefine fixtext mode=output intype=text/html cmd="/bin/sed \'s,/o_o_hmyuan_com,,g\'"
    SetOutputFilter fixtext','2017-05-03 16:05:56','65','0','','1','~~fileDomainName~~//img/201706/1497511978128.jpg','问题：使用Apache代理tomcat时，遇到session丢失导致网站不能登录
问题分析：通过Apache代理之后，tomcat工程原来的访问路径（https://hmyuan.com/hmyuan/ ）改变为（https://hmyuan.com）导致sessionid找不到，只要在Apache里做好相应的路径映射就可以解决问题了
解决方法：修改Apache配置文件Prox...','admin','Apache反向代理tomcat时session丢失'),
('49','2','#问题：
给网站添加ssl证书时，由于浏览器输入域名请求时默认使用的http协议，如果想要使用https协议访问还要输入协议名称\'https://\' ,用户体验方面不是很好。
因此，现在要实现免去输入\'https://\' 而直接使用https协议请求网站。

#分析：
http请求和https请求的不同之处在于协议头不一样，只要在服务器端判断一下，如果是http请求就将其重定向至相应的https地址即可。
#解决方案：
####修改apache配置如下：
	<VirtualHost *:80>
		ServerAdmin webmaster@example.com
		ServerAlias hmyuan.com
		RewriteEngine on
		RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [L,R]
	</VirtualHost>','2017-05-17 23:32:03','39','0','','1','~~fileDomainName~~//img/201706/1497511857011.jpg','问题：给网站添加ssl证书时，由于浏览器输入域名请求时默认使用的http协议，如果想要使用https协议访问还要输入协议名称’https://‘ ,用户体验方面不是很好。因此，现在要实现免去输入’https://‘ 而直接使用https协议请求网站。
分析：http请求和https请求的不同之处在于协议头不一样，只要在服务器端判断一下，如果是http请求就将其重定向至相应的ht...','admin','apache配置http重定向至https'),
('38','2','','2017-04-12 14:30:14','0','2','tags','101','o0o/tags','E89A','admin','标签云'),
('39','2','#请留下您的脚印！谢谢！','2017-04-13 11:26:58','594','2','massage','100','~~fileDomainName~~//img/201706/1497518199103.jpg','E8DF','admin','留言板'),
('40','2','','2017-04-13 12:48:30','0','2','','101','','E88A','admin','首页'),
('50','2','#问题描述：
最近按照公司业务要求做一个相当繁琐的客户积分消费接口，在接口测试的过程中发现Spring中配置的事务（@Transactional）并没有生效（注：工程框架是我刚刚搭建的）
#问题分析和解决：
####1.检查相关配置
工程中的事务都是通过（@Transactional）注解控制配置，由Spring统一管理的，因此考虑到时Spring-Mybatis.xml中没配好。
仔细检查事务的相关配置感觉没有问题，
```xml
<!-- transaction support-->
<!-- PlatformTransactionMnager -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" ></property>
</bean>
<!-- enable transaction annotation support -->
<tx:annotation-driven transaction-manager="txManager" ></tx:annotation-driven>
```
最后不经意间发现spring多个配置文件中引入的xsd标签版本不统一，
统一修改xsd版本到3.2后测试事务竟然生效了
```xml
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:tx="http://www.springframework.org/schema/tx"  
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                        http://www.springframework.org/schema/tx
          				http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-3.2.xsd
                        http://www.springframework.org/schema/mvc
                        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
```
####2.出现异常时事务只被部分回滚
问题总算解决了一部分，然后发现新问题又出现了，
`当一个方法里有多条更新语句，并且更新语句之间存在查询语句时，查询语句会将事务分成两个进行提交`
这句话其实有问题，之前是这样认为的。
找了很久发现是执行的那个“查询语句”有问题，查询语句是调用的是“存储过程”，而“存储过程”中有一个提交事务的命令**commit**，是这个命令导致的“事务分开提交”的假象。
#总结
问题总算解决了，感觉还是不完美，还有很多疑问，比如：1.引入的xsd标签为什么要用3.2版本，2.之前写存储过程的那个人问什么要在里面使用**commit**命令。
我还是很菜，还要向着我向往的明天继续努力！:tw-1f60a: :tw-1f609:','2017-06-05 17:06:07','34','0','','1','~~fileDomainName~~//img/201706/1497511691979.jpg','问题描述：最近按照公司业务要求做一个相当繁琐的客户积分消费接口，在接口测试的过程中发现Spring中配置的事务（@Transactional）并没有生效（注：工程框架是我刚刚搭建的）
问题分析和解决：1.检查相关配置工程中的事务都是通过（@Transactional）注解控制配置，由Spring统一管理的，因此考虑到时Spring-Mybatis.xml中没配好。仔细检查事务的...','admin','spring事务（@Transactional）配置不生效'),
('51','2','#问题描述
最近做公司里的接口工程，请求每个接口时都要做统一的接入码认证，如果在每个接口里都写上接入码校验的代码则会出现很多冗余的代码。
因此，我想使用Spring自定义注解加上aop方式实现请求拦截并加以验证。
虽然之前写过通过自定义注解记录操作日志的功能，但是一时忘记了，只好又重新研究了一下。

#解决过程
####1.根据这篇文章完成相应的代码
http://blog.csdn.net/paincupid/article/details/50534412
####2.配置完成后，代码未生效
问题总是会有的，配置完成之后aop没有生效，查看了各部分代码和相关配置都没有问题。又回头看这篇文章，发现这句话（之前也看到了，以为没问题就没管）
```xml
<!-- 最重要:::如果放在spring-context.xml中，这里的aop设置将不会生效 -->
<aop:aspectj-autoproxy proxy-target-class="true" ></aop:aspectj-autoproxy>
```
于是新建了spring-context-aop.xml文件，将上面的配置放进去，
哈哈哈！:tw-1f606:这次还是没成功！:tw-1f605:
不过不要紧，继续找问题。
突然想到，这个功能既然是交给Spring管理的，那这个配置一定需要配置“扫描注入”，机智的我在spring-context-aop.xml文件中添加了如下配置
```xml
 <!-- 对指定的包进行组件扫描 -->
 <context:component-scan base-package="com.hmyuan" ></context:component-scan>
```
哈。。。！:tw-1f606:这次可以开心的笑了！哈哈哈哈哈！:tw-1f61c:
自定义注解拦截终于成功了。
####3.记录日志和验证功能实现的区别
两个功能肯定是有区别的。
#####记录日志功能比较简单只需要一下方式即可
```java
@Pointcut("@annotation(com.hmyuan.log.OpLogger)")
public void controllerAspect() {
}
@Before("controllerAspect()")
public void doBefore(JoinPoint joinPoint) {
	System.out.println("=====SysLogAspect前置通知开始=====");
}
@AfterReturning(pointcut="controllerAspect()")
public  void doAfter(JoinPoint joinPoint) {
	System.out.println("=====SysLogAspect后置通知开始=====");
	//这里写记录日志的代码
}
@AfterThrowing(value="controllerAspect()",throwing="e")
public void doAfter(JoinPoint joinPoint, Exception e) {
	System.out.println("=====SysLogAspect异常通知开始=====");
}
```
#####拦截校验实现方式(日志记录也可以使用这种方式)
```java
/**aop实际拦截*/
@Around("controllerAspect()")
public Object doBefore(ProceedingJoinPoint joinPoint) {
    Map<String, Object> result = new HashMap<String, Object>();
    //访问目标方法的参数：
    Object[] args = joinPoint.getArgs();
    // 获取目标方法签名
    String signature = joinPoint.getSignature().toString();   
    try {
        //判断最后一个参数是否为Map
        if(args!=null&&args.length>0&&args[args.length-1] instanceof Map){
            Map param = (Map) args[args.length-1];
            Object pwd= param.get("pwd");
            //判断参数是否为空
            if(null==pwd||
                    StringUtils.isEmpty((CharSequence) pwd)){
                result.put("errCode", "1");
                return result;
            }else{
                String password = "校验码"；
                if(null==asc||!pwd.equals(password)){
                    //认证不通过，直接返回错误提示
                    result.put("errCode", "1");
                    return result;
                }else{
                    //认证通过，继续执行函数
                    return joinPoint.proceed();
                }
            }
        }else{
            result.put("errCode", "100");
            logger.info("认证出现异常-{} 异常信息：{}", signature,"被认证的接口传递的最后一个参数必须为Map");
            return result;
        }
    } catch (Throwable e) {
        // TODO Auto-generated catch block
        result.put("errCode", "100");
        logger.info("认证出现异常-{} 异常信息：{}", signature,e);
        return result;
    }
}
```
在这个方法中return返回的对象会交给Spring处理（原来方法的返回对象的处理方式处理）例如：原来使用@responseBody返回json字符串，程序仍然会将这里返回的对象转为json字符串并返回
注：上面这两种方式也是可以共生的
#总结
####1.好记星不如烂笔头
以前做过的功能时间长了也会忘记，以后要记得多学多记
####2.笔记固然重要，但是解决问题的方法和能力更重要
新的业务要求一致在出现，问题也会随之出现，在新问题出现的时候不要慌，认真分析，总会找到解决的方法的。','2017-06-06 16:54:34','65','0','','1','~~fileDomainName~~//img/201706/1497511570718.jpg','问题描述最近做公司里的接口工程，请求每个接口时都要做统一的接入码认证，如果在每个接口里都写上接入码校验的代码则会出现很多冗余的代码。因此，我想使用Spring自定义注解加上aop方式实现请求拦截并加以验证。虽然之前写过通过自定义注解记录操作日志的功能，但是一时忘记了，只好又重新研究了一下。
解决过程1.根据这篇文章完成相应的代码http://blog.csdn.net/pain...','admin','Spring自定义注解（aop）实现拦截和认证'),
('52','2','#需求
自己做的博客项目（hmyuan.com）中需要图片上传的功能，而上传的图片大小、尺寸等都不一定。
考虑各方面情况需要实现以下功能:
1.对上传图片的质量压缩
2.对上传图片的尺寸过大的进行尺寸压缩，较小的尺寸保持不变
3.为图片添加水印

#功能实现
####1.使用Thumbnailator类库
Thumbnailator 是一个用来生成图像缩略图的 Java 类库 支持：图片缩放，区域裁剪，水印，旋转，保持比例。
工程中（pom.xm）引入类库:
```xml
<!-- Thumbnailator 是一个用来生成图像缩略图的 Java 类库 支持：图片缩放，区域裁剪，水印，旋转，保持比例 -->
<!-- https://mvnrepository.com/artifact/net.coobird/thumbnailator -->
<dependency>
	<groupId>net.coobird</groupId>
	<artifactId>thumbnailator</artifactId>
	<version>0.4.8</version>
</dependency>
```
####2.java代码
Thumbnailator对于简单的图片压缩功能实现非常简单，
参考文章：http://www.cnblogs.com/daily-note/p/5505709.html
```java
//1.Thumbnailator对图片进行指定尺寸的压缩。
public void testYS1() throws IOException {
	String result = "src/main/resources/images/";
	Thumbnails.of(result + "sijili.jpg").size(200, 300).toFile(result + "image_200x300.jpg");
}
//2.Thumbnailator对图片进行指定比例的压缩。
public void testYS2() throws IOException {
	String result = "src/main/resources/images/";
	Thumbnails.of(result + "sijili.jpg").scale(0.5f).toFile(result + "image_0.5f.jpg");
}
//3.Thumbnailator对图片进行旋转。
public void testYS3() throws IOException {
	String result = "src/main/resources/images/";
	Thumbnails.of(result + "sijili.jpg").scale(1.0f).rotate(180).toFile(result + "image_r180.jpg");
}
//4.Thumbnailator对图片进行格式转换。
public void testYS4() throws IOException {
	String result = "src/main/resources/images/";
	Thumbnails.of(result + "sijili.jpg").scale(1.0f).outputFormat("png").toFile(result + "image_sijiali.png");
}
```
####要实现自己想要的功能需要做相应的变通
查看Thumbnails中的of方法重载有以下几种
```java
of(BufferedImage arg0);
of(File arg0);
of(InputStream arg0);
of(String arg0);
of(URL arg0);
```
使用of(BufferedImage arg0)代码实现如下（生产水印图片部分忽略）
```java
//生成水印图片
ImgForText vCode = new ImgForText(400,60,waterOfImg);

BufferedImage bufferedImage = ImageIO.read(upfile.getInputStream());
int width = bufferedImage.getWidth();
//宽度超过1000则进行尺寸压缩
if(width>1000){
	// watermark 参数 1.位置 2.水印图片 3.透明度
	Thumbnails.of(bufferedImage)
		.size(1000, 2000)
		.watermark(Positions.CENTER, vCode.getBuffImg(), 0.25f)
		.toFile(yuantuPathRoot+filePath);
}else{
	// watermark 参数 1.位置 2.水印图片 3.透明度
	Thumbnails.of(bufferedImage)
		.scale(1.0f)
		.watermark(Positions.CENTER, vCode.getBuffImg(), 0.25f)
		.toFile(yuantuPathRoot+filePath);
}
```
#总结
功能很简单就不总结了，写这个文章的目的主要记录一下这个工具（Thumbnails）的功能。','2017-06-07 15:53:10','90','0','','1','~~fileDomainName~~//img/201706/1497511380128.jpg','需求自己做的博客项目（hmyuan.com）中需要图片上传的功能，而上传的图片大小、尺寸等都不一定。考虑各方面情况需要实现以下功能:1.对上传图片的质量压缩2.对上传图片的尺寸过大的进行尺寸压缩，较小的尺寸保持不变3.为图片添加水印
功能实现1.使用Thumbnailator类库Thumbnailator 是一个用来生成图像缩略图的 Java 类库 支持：图片缩放，区域裁剪，水...','admin','java图片压缩、加水印'),
('53','2','#需求
Java是一门静态语言，通常，我们需要的class在编译的时候就已经生成了，为什么有时候我们还想在运行时动态生成class呢？
因为在有些时候，我们还真得在运行时为一个类动态创建子类。比如，编写一个ORM框架，如何得知一个简单的JavaBean是否被用户修改过呢？
参考：http://www.liaoxuefeng.com/article/0014617596492474eea2227bf04477e83e6d094683e0536000

#最简单的一种方法
参考：https://github.com/michaelliao/compiler
###How to use this compiler?

####Step 1: add maven dependency:
```xml
<dependency>
    <groupId>com.itranswarp</groupId>
    <artifactId>compiler</artifactId>
    <version>1.0</version>
</dependency>
```
####Step 2: compile string and load class:
```java
public class Main {
    public static void main(String[] args) {
        JavaStringCompiler compiler = new JavaStringCompiler();
        Map<String, byte[]> results = compiler.compile("UserProxy.java", JAVA_SOURCE_CODE);
        Class<?> clazz = compiler.loadClass("on.the.fly.UserProxy", results);
        // try instance:
        User user = (User) clazz.newInstance();
    }
    static final String JAVA_SOURCE_CODE = "/* a single java source file */   "
            + "package on.the.fly;                                            "
            + "public class UserProxy extends test.User {                     "
            + "    boolean _dirty = false;                                    "
            + "    public void setId(String id) {                             "
            + "        super.setId(id);                                       "
            + "        setDirty(true);                                        "
            + "    }                                                          "
            + "    public void setName(String name) {                         "
            + "        super.setName(name);                                   "
            + "        setDirty(true);                                        "
            + "    }                                                          "
            + "    public void setCreated(long created) {                     "
            + "        super.setCreated(created);                             "
            + "        setDirty(true);                                        "
            + "    }                                                          "
            + "    public void setDirty(boolean dirty) {                      "
            + "        this._dirty = dirty;                                   "
            + "    }                                                          "
            + "    public boolean isDirty() {                                 "
            + "        return this._dirty;                                    "
            + "    }                                                          "
            + "}                                                              ";
}
```','2017-06-21 09:58:14','26','0','','1','~~fileDomainName~~//img/201706/1498010891219.jpg','需求Java是一门静态语言，通常，我们需要的class在编译的时候就已经生成了，为什么有时候我们还想在运行时动态生成class呢？因为在有些时候，我们还真得在运行时为一个类动态创建子类。比如，编写一个ORM框架，如何得知一个简单的JavaBean是否被用户修改过呢？参考：http://www.liaoxuefeng.com/article/0014617596492474eea...','admin','Java运行时动态生成class的方法'),
('54','2','##需求
使用IntelliJ IDEA开发工具时，选择旗舰版（Ultimate）功能比社区办（Community）要多，但是旗舰版需要注册码才能使用。
于是就要用到接下来的破解之路！
##激活方式
###1.你需要下载一个JetbrainsCrack.jar包
下载地址：http://idea.lanyus.com/jar/JetbrainsCrack-2.6.2.jar 
idea14 keygen使用下面的地址
下载地址：http://idea.lanyus.com/jar/JetbrainsPatchKeygen-1.2.1.jar
###2.把jar包复制到要激活的 jetbrains 产品的bin目录下
如：`D:\\Program Files (x86)\\JetBrains\\WebStorm 2016.3.2\\bin`
###3.修改bin目录下的.vmoptions文件
如：webstorm.exe.vmoptions
在该文件最后添加JetbrainsCrack.jar路径：
`-javaagent: D:/Program Files (x86)/JetBrains/WebStorm 2016.3.2/bin/JetbrainsCrack.jar`
注：如果要用64位的把对应的64.vmoptions文件也做上述修改
###4.启动Jetbrains产品，选择Activation code激活，
选择Activation code后复制到Jetbrains产品的Activation code即可激活。用户名和邮箱随便写，时间改不改无所谓。

**Activation code代码如下：**
```json
ThisCrackLicenseId-{
"licenseId":"ThisCrackLicenseId",
"licenseeName":"你的用户名",
"assigneeName":"",
"assigneeEmail":"你的邮箱",
"licenseRestriction":"For This Crack, Only Test! Please support genuine!!!",
"checkConcurrentUse":false,
"products":[
{"code":"II","paidUpTo":"2099-12-31"},
{"code":"DM","paidUpTo":"2099-12-31"},
{"code":"AC","paidUpTo":"2099-12-31"},
{"code":"RS0","paidUpTo":"2099-12-31"},
{"code":"WS","paidUpTo":"2099-12-31"},
{"code":"DPN","paidUpTo":"2099-12-31"},
{"code":"RC","paidUpTo":"2099-12-31"},
{"code":"PS","paidUpTo":"2099-12-31"},
{"code":"DC","paidUpTo":"2099-12-31"},
{"code":"RM","paidUpTo":"2099-12-31"},
{"code":"CL","paidUpTo":"2099-12-31"},
{"code":"PC","paidUpTo":"2099-12-31"}
],
"hash":"2911276/0",
"gracePeriodDays":7,
"autoProlongated":false}
```
###到这里应该已经激活成功了！
如果发现Jetbrains更新后激活失效了，那么就到网上下载新版本的JetbrainsCrack.jar。','2017-06-22 13:56:43','23','0','','1','~~fileDomainName~~//img/201706/1498110987983.png','需求使用IntelliJ IDEA开发工具时，选择旗舰版（Ultimate）功能比社区办（Community）要多，但是旗舰版需要注册码才能使用。于是就要用到接下来的破解之路！
激活方式1.你需要下载一个JetbrainsCrack.jar包下载地址：http://idea.lanyus.com/jar/JetbrainsCrack-2.6.2.jaridea14使用下面的地址...','admin','IntelliJ IDEA破解补丁jetbrains'),
('55','2','##问题
使用百度站长工具检查网站（ https://hmyuan.com ）时，提示“网站没有全部使用安全链接，如（http://hmyuan.com ）”,
令我不解的是我明明对http协议做了重定向到https了，难道还有其他什么比较好的方法，而我不知道吗？
##分析
百度搜索同样会把http重定向到https，难道他就不怕不安全吗？
1.打开浏览器输入（http://baidu.com ）,抓包发现链接重定向到（https://baidu.com ）,而重定向的返回码是：307
2.打开我的个人网站（http://hmyuan.com ）,同样重定向到了https相关链接，而重定向的返回码是：302
这下看来确实有不一样的地方，但是307和302到底有什么区别呢？
##相关文章
参考：http://blog.sina.com.cn/s/blog_62ec29160101f3u3.html
--301 永久重定向,告诉客户端以后应从新地址访问.
--302 作为HTTP1.0的标准,以前叫做Moved Temporarily ,现在叫Found. 现在使用只是为了兼容性的处理,包括PHP的默认Location重定向用的也是302.
但是HTTP 1.1 有303 和307作为详细的补充,其实是对302的细化
--303：对于POST请求，它表示请求已经被处理，客户端可以接着使用GET方法去请求Location里的URI。
--307：对于POST请求，表示请求还没有被处理，客户端应该向Location里的URI重新发起POST请求。

####实际测试:
#####测试内容:
写一个测试的test.html代码,发起post请求到test.php页面中
test.php页面分别给出3种重定向处理,都跳到test2.php
test2.php打印出post的结果
(至于怎么写..自己查手册吧,PHP发送头很容易.)
```
301 => "HTTP/1.1 301 Moved Permanently",
302 => "HTTP/1.1 302 Found",
303 => "HTTP/1.1 303 See Other",
307 => "HTTP/1.1 307 Temporary Redirect",
```
测试结果:
301,302和303的处理结果是一样的,直接跳转到test2.php,post没有内容
307的会重新post请求到test2.php,并且给出页面提示
##解决方式
###原配置文件：
```xml
<VirtualHost *:80>
    ServerAdmin webmaster@example.com
    ServerAlias hmyuan.com
    RewriteEngine on
    RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [L,R]
</VirtualHost>
```
将最后的`[L,R]`改为`[R=307,L]`
###修改后：
```xml
<VirtualHost *:80>
    ServerAdmin webmaster@example.com
    ServerAlias hmyuan.com
    RewriteEngine on
    RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [R=307,L]
</VirtualHost>
```
###修改完成后检查仍未通过，提示信息如下
百度https检查提示：
![](~~fileDomainName~~/img/201706/1498186363266.png)
![](~~fileDomainName~~/img/201706/1498180299756.png)
###继续修改
改为`[R=301,L]`
很遗憾的是这一次还是没有成功，错误提示与`[L,R]`时相同。
没有搞明白为什么，先不管了。百度已经做的很好了，但是与google相比还是有一定距离。也不知道google什么时候能再次进入大陆市场。','2017-06-22 21:32:16','27','0','','1','~~fileDomainName~~//img/201706/1498138326881.jpg','问题使用百度站长工具检查网站（ https://hmyuan.com ）时，提示“网站没有全部使用安全链接，如（http://hmyuan.com ）”,令我不解的是我明明对http协议做了重定向到https了，难道还有其他什么比较好的方法，而我不知道吗？
分析百度搜索同样会把http重定向到https，难道他就不怕不安全吗？1.打开浏览器输入（http://baidu.com...','admin','HTTP 的重定向301,302,303,307'),
('56','2','转自：http://www.open-open.com/lib/view/open1452046967245.html
原出处：http://www.hollischuang.com/archives/934
在数据库的锁机制中介绍过，数据库管理系统（DBMS）中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。

乐观并发控制(乐观锁)和悲观并发控制（悲观锁）是并发控制主要采用的技术手段。

无论是悲观锁还是乐观锁，都是人们定义出来的概念，可以认为是一种思想。其实不仅仅是数据库系统中有乐观锁和悲观锁的概念，像memcache、hibernate、tair等都有类似的概念。

针对于不同的业务场景，应该选用不同的并发控制方式。所以，不要把乐观并发控制和悲观并发控制狭义的理解为DBMS中的概念，更不要把他们和数据中提供的锁机制（行锁、表锁、排他锁、共享锁）混为一谈。其实，在DBMS中，悲观锁正是利用数据库本身提供的锁机制来实现的。

下面来分别学习一下悲观锁和乐观锁。

#1.悲观锁
在关系数据库管理系统里，悲观并发控制（又名“悲观锁”，Pessimistic Concurrency Control，缩写“PCC”）是一种并发控制的方法。它可以阻止一个事务以影响其他用户的方式来修改数据。如果一个事务执行的操作都某行数据应用了锁，那只有当这个事务把锁释放，其他事务才能够执行与该锁冲突的操作。悲观并发控制主要用于数据争用激烈的环境，以及发生并发冲突时使用锁保护数据的成本要低于回滚事务的成本的环境中。

悲观锁，正如其名，它指的是对数据被外界（包括本系统当前的其他事务，以及来自外部系统的事务处理）修改持保守态度(悲观)，因此，在整个数据处理过程中，将数据处于锁定状态。 悲观锁的实现，往往依靠数据库提供的锁机制 （也只有数据库层提供的锁机制才能真正保证数据访问的排他性，否则，即使在本系统中实现了加锁机制，也无法保证外部系统不会修改数据）

##1.1在数据库中，悲观锁的流程如下：
在对任意记录进行修改前，先尝试为该记录加上排他锁（exclusive locking）。

如果加锁失败，说明该记录正在被修改，那么当前查询可能要等待或者抛出异常。 具体响应方式由开发者根据实际需要决定。

如果成功加锁，那么就可以对记录做修改，事务完成后就会解锁了。

其间如果有其他对该记录做修改或加排他锁的操作，都会等待我们解锁或直接抛出异常。

##1.2MySQL InnoDB中使用悲观锁
要使用悲观锁，我们必须关闭mysql数据库的自动提交属性，因为MySQL默认使用autocommit模式，也就是说，当你执行一个更新操作后，MySQL会立刻将结果进行提交。 set autocommit=0;

```sql
//0.开始事务
begin;/begin work;/start transaction; (三者选一就可以)
//1.查询出商品信息
select status from t_goods where id=1 for update;
//2.根据商品信息生成订单
insert into t_orders (id,goods_id) values (null,1);
//3.修改商品status为2
update t_goods set status=2;
//4.提交事务
commit;/commit work;
```
上面的查询语句中，我们使用了 select…for update 的方式，这样就通过开启排他锁的方式实现了悲观锁。此时在t_goods表中，id为1的 那条数据就被我们锁定了，其它的事务必须等本次事务提交之后才能执行。这样我们可以保证当前的数据不会被其它事务修改。

上面我们提到，使用 select…for update 会把数据给锁住，不过我们需要注意一些锁的级别，MySQL InnoDB默认行级锁。行级锁都是基于索引的，如果一条SQL语句用不到索引是不会使用行级锁的，会使用表级锁把整张表锁住，这点需要注意。

##1.3优点与不足
悲观并发控制实际上是“先取锁再访问”的保守策略，为数据处理的安全提供了保证。但是在效率方面，处理加锁的机制会让数据库产生额外的开销，还有增加产生死锁的机会；另外，在只读型事务处理中由于不会产生冲突，也没必要使用锁，这样做只能增加系统负载；还有会降低了并行性，一个事务如果锁定了某行数据，其他事务就必须等待该事务处理完才可以处理那行数

#2.乐观锁
在关系数据库管理系统里，乐观并发控制（又名“乐观锁”，Optimistic Concurrency Control，缩写“OCC”）是一种并发控制的方法。它假设多用户并发的事务在处理时不会彼此互相影响，各事务能够在不产生锁的情况下处理各自影响的那部分数据。在提交数据更新之前，每个事务会先检查在该事务读取数据后，有没有其他事务又修改了该数据。如果其他事务有更新的话，正在提交的事务会进行回滚。乐观事务控制最早是由孔祥重（H.T.Kung）教授提出。

乐观锁（ Optimistic Locking ） 相对悲观锁而言，乐观锁假设认为数据一般情况下不会造成冲突，所以在数据进行提交更新的时候，才会正式对数据的冲突与否进行检测，如果发现冲突了，则让返回用户错误的信息，让用户决定如何去做。

相对于悲观锁，在对数据库进行处理的时候，乐观锁并不会使用数据库提供的锁机制。一般的实现乐观锁的方式就是记录数据版本。

数据版本,为数据增加的一个版本标识。当读取数据时，将版本标识的值一同读出，数据每更新一次，同时对版本标识进行更新。当我们提交更新的时候，判断数据库表对应记录的当前版本信息与第一次取出来的版本标识进行比对，如果数据库表当前版本号与第一次取出来的版本标识值相等，则予以更新，否则认为是过期数据。

实现数据版本有两种方式，第一种是使用版本号，第二种是使用时间戳。

##2.1使用版本号实现乐观锁
使用版本号时，可以在数据初始化时指定一个版本号，每次对数据的更新操作都对版本号执行+1操作。并判断当前版本号是不是该数据的最新的版本号。

1.查询出商品信息
```sql
select (status,status,version) from t_goods where id=#{id}
```
2.根据商品信息生成订单
3.修改商品status为2
```sql
update t_goods set status=2,version=version+1 where id=#{id} and version=#{version};
```
##2.2优点与不足
乐观并发控制相信事务之间的数据竞争(data race)的概率是比较小的，因此尽可能直接做下去，直到提交的时候才去锁定，所以不会产生任何锁和死锁。但如果直接简单这么做，还是有可能会遇到不可预期的结果，例如两个事务都读取了数据库的某一行，经过修改以后写回数据库，这时就遇到了问题。','2017-06-22 21:51:44','16','0','','1','~~fileDomainName~~//img/201706/1498139497007.jpg','在数据库的锁机制中介绍过，数据库管理系统（DBMS）中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。
乐观并发控制(...','admin','关于数据库乐观锁与悲观锁'),
('57','2','####公共库链接：https://css.net/

常用前端公共库 CDN 服务
常用前端公共库 & 和谐使用 Google 公共库、字体库的方法

####如何使用> https://ttt.tt/185/
####常用前端公共库 https://cdn.css.net/
####Google 公共库 https://ajax.css.network/
####Gravatar https://gravatar.css.network/
####Google 字体库 https://fonts.css.network/','2017-06-28 10:10:22','10','0','','1','~~fileDomainName~~//img/201706/1498615809801.jpg','公共库链接：https://css.net/常用前端公共库 CDN 服务常用前端公共库 & 和谐使用 Google 公共库、字体库的方法
如何使用> https://ttt.tt/185/常用前端公共库 https://cdn.css.net/Google 公共库 https://ajax.css.network/Gravatar https://gravatar.css.ne...','admin','常用前端公共库 & 和谐使用 Google 公共库、字体库的方法'),
('58','2','参考：http://www.cnblogs.com/rabbit2012/archive/2013/03/15/2961881.html
###需求
随着DOM结构的复杂化和Ajax等动态脚本技术的运用，有了较多的动态添加进来的元素，直接用JQ添加click事件会发现新添加进来的元素并不能直接选取到，在这里就需要用到事件委托方法，JQ为事件委托提供了live（）、dalegate（）和on（）方法。   

###事件委托
我们知道，DOM在为页面中的每个元素分派事件时，相应的元素一般都在事件冒泡阶段处理事件。在类似 body > div > a 这样的结构中，如果单击a元素，click事件会从a一直冒泡到div和body（即document对象）。因此，发生在a上面的单击事件，div和body元素同样可以处理。而利用事件传播（这里是冒泡）这个机制，就可以实现事件委托。具体来说，事件委托就是事件目标自身不处理事件，而是把处理任务委托给其父元素或者祖先元素，甚至根元素（document）。

###.live()
jQuery 1.3新增的live()方法，用法如下：
```javascript
$("#info_table td").live("click",function(){/*显示更多信息*/});
```
这里的.live()方法会把click事件绑定到$(document)对象，而且只需要给$(document)绑定一次，然后就能够处理后续动态加载的单元格的单击事件。在接收到任何事件时，$(document)对象都会检查事件类型和事件目标，如果是click事件且事件目标是td，那么就执行委托给它的处理程序。
###.delegate()
如前所述，为了突破单一.bind()方法的局限性，实现事件委托，jQuery 1.3引入了.live()方法。后来，为解决“事件传播链”过长的问题，jQuery 1.4又支持为.live()方法指定上下文对象。而为了解决无谓生成元素集合的问题，jQuery 1.4.2干脆直接引入了一个新方法.delegate()。

使用.delegate()，前面的例子可以这样写：

```javascript
$("#info_table").delegate("td","click",function(){/*显示更多信息*/});
```
使用.delegate()有如下优点（或者说解决了.live()方法的如下问题）：

直接将目标元素选择符（"td"）、事件（"click"）及处理程序与“受拖方”$("#info_table")绑定，不额外收集元素、事件传播路径缩短、语义明确；
支持在连缀的DOM遍历方法后面调用，即支持$("table").find("#info").delegate...，支持精确控制；
可见，.delegate()方法是一个相对完美的解决方案。但在DOM结构简单的情况下，也可以使用.live()。

提示：使用事件委托时，如果注册到目标元素上的其他事件处理程序使用.stopPropagation()阻止了事件传播，那么事件委托就会失效。

###在下列情况下，应该使用.live()或.delegate()，而不能使用.bind()：

为DOM中的很多元素绑定相同事件；
为DOM中尚不存在的元素绑定事件；','2017-06-29 12:43:45','6','0','','1','~~fileDomainName~~//img/201706/1498711416014.jpg','参考：http://www.cnblogs.com/rabbit2012/archive/2013/03/15/2961881.html
需求随着DOM结构的复杂化和Ajax等动态脚本技术的运用，有了较多的动态添加进来的元素，直接用JQ添加click事件会发现新添加进来的元素并不能直接选取到，在这里就需要用到事件委托方法，JQ为事件委托提供了live（）、dalegate（）和...','admin','Jquery为未来元素添加事件处理器—事件委托'),
('59','2','转载：http://www.itshij.com/divresize
###今天，小编给大家整理的是监听div大小变化的jquery扩展，通过这个函数扩展jquery，使div也具有和窗口一样的resize功能
```javascript
//监听div大小变化
(function($, h, c) {
	var a = $([]),
	e = $.resize = $.extend($.resize, {}),
	i,
	k = "setTimeout",
	j = "resize",
	d = j + "-special-event",
	b = "delay",
	f = "throttleWindow";
	e[b] = 250;
	e[f] = true;
	$.event.special[j] = {
		setup: function() {
			if (!e[f] && this[k]) {
				return false;
			}
			var l = $(this);
			a = a.add(l);
			$.data(this, d, {
				w: l.width(),
				h: l.height()
			});
			if (a.length === 1) {
				g();
			}
		},
		teardown: function() {
			if (!e[f] && this[k]) {
				return false;
			}
			var l = $(this);
			a = a.not(l);
			l.removeData(d);
			if (!a.length) {
				clearTimeout(i);
			}
		},
		add: function(l) {
			if (!e[f] && this[k]) {
				return false;
			}
			var n;
			function m(s, o, p) {
				var q = $(this),
				r = $.data(this, d);
				r.w = o !== c ? o: q.width();
				r.h = p !== c ? p: q.height();
				n.apply(this, arguments);
			}
			if ($.isFunction(l)) {
				n = l;
				return m;
			} else {
				n = l.handler;
				l.handler = m;
			}
		}
	};
	function g() {
		i = h[k](function() {
			a.each(function() {
				var n = $(this),
				m = n.width(),
				l = n.height(),
				o = $.data(this, d);
				if (m !== o.w || l !== o.h) {
					n.trigger(j, [o.w = m, o.h = l]);
				}
			});
			g();
		},
		e[b]);
	}
})(jQuery, this);
```
###下面是调用方法

```javascript
$("#main").resize(function(){
    //当id为main的div大小变化时的处理函数写在这里.....
    //当然了#main只不过是id选择器，你也可以换成任何jquery的选择器......
});
```','2017-06-29 14:24:57','10','0','','1','~~fileDomainName~~//img/201706/1498717491480.jpg','转载：http://www.itshij.com/divresize
今天，小编给大家整理的是监听div大小变化的jquery扩展，通过这个函数扩展jquery，使div也具有和窗口一样的resize功能//监听div大小变化(function($, h, c) {    var a = $([]),    e = $.resize = $.extend($.resize, {...','admin','jquery 监听div大小变化函数|div resize事件'),
('60','2','参考：[百度百科](http://baike.baidu.com/item/JAVA%E5%8F%8D%E5%B0%84%E6%9C%BA%E5%88%B6 "百度百科")
###JAVA反射机制
![](~~fileDomainName~~/img/201707/1500727715935.jpg)
JAVA反射机制是在运行状态中，对于任意一个类，都能够知道这个类的所有属性和方法；对于任意一个对象，都能够调用它的任意方法和属性；这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

参考：http://blog.csdn.net/mlc1218559742/article/details/52767156
代理模式的核心思路就是一个接口有两个子类，一个子类完成核心的业务操作，另一个子类完成与核心业务有关的辅助性操作。
代理模式分为静态代理模式和动态代理模式。
###静态代理模式：
```java
//接口类  
interface Food{  
    public void eat();  
}  
//核心业务操作类  
class RealFood implements Food{  
    @Override  
    public void eat() {  
        System.out.println("马小超在吃饭！");  
    }  
}  
//与核心业务有关的辅助性操作  
class ProxyFood implements Food{  
    private Food food;  
      
    public Food bind(Food food){  
        this.food = food;  
        return this;  
    }  
    @Override  
    public void eat() {  
        this.prepare();  
        this.food.eat();  
        this.after();  
    }  
    private void prepare(){  
        System.out.println("吃饭钱准备：洗手");  
    }  
    private void after(){  
        System.out.println("吃饭后收拾：洗碗");  
    }  
}  
//测试类  
public class StaticProxy {  
    public static void main(String[] args){  
        Food food = new ProxyFood().bind(new RealFood());  
        food.eat();  
    }  
}  
```
####输出结果：
```java
吃饭钱准备：洗手  
马小超在吃饭！  
吃饭后收拾：洗碗 
```
如上代码所示，定义一个接口类Food，定义一个实现类RealFood来完成核心业务操作，同时再定义一个代理类ProxyFood来完成与核心业务相关的辅助操作。
在代理类ProxyFood中引入代理对象food，定义辅助操作的方法，在重写的eat()方法中引用辅助操作方法。代码如上面所示。
静态的代理模式都是一个接口两个子类，这样一来就会导致一个类只能为一个接口服务。如果有几十个接口，那项目就别做了，这样的设计有很明显的缺陷。那么怎么样才能解决这个问题了？利用反射就可以解决啦。


###动态代理模式： 
要实现动态代理，则必须实现反射包中的InvocationHandler接口，该接口中只定义了一个invoke()方法，在代理实例上处理方法调用并返回结果。
```java
Object invoke(Object proxy,Method method,Object[] args)throws Throwable
```
invoke()方法接受的参数如下：
	proxy：需要代理的对象
	method：表示真实主体要调用的执行方法
	args：调用方法时（上面的method代表的方法）传递的参数
在调用invoke()方法时，所有的真实主体类都需要返回一个代理对象，而这个代理对象由Porxy类中的newProxyInstance方法来完成。
```java
public static Object newProxyInstance(ClassLoader loader,  
                                      Class<?>[] interfaces,  
                                      InvocationHandler h)  
                               throws IllegalArgumentException  
```
该方法返回一个指定接口的代理实例，这个指定接口可以将方法调用指派到指定的调用处理程序。
newProxyInstance需要的参数如下：
       loader：定义被代理类的类加载器。
       interfaces：被代理类要实现接口列表
       h：指派方法调用的调用处理程序，用被代理类的实例创建动态代理类的实例，用于真正调用处理程序
####代码如下：
```java
import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;  
import java.lang.reflect.Proxy;  
//接口类  
interface DaoI{  
    public void doSave();  
    public Object getById(String id);  
}  
//DaoI实现类,真实主体类，即被代理类  
class DaoImpl implements DaoI{  
    @Override  
    public void doSave() {  
        System.out.println("执行保存方法【doSave】");  
    }  
    @Override  
    public Object getById(String id) {  
        System.out.println("执行根据ID查找对象方法【getById】");  
        return null;  
    }  
}  
//InvocationHandler实现类  
class DaoProxy implements InvocationHandler{  
    //被代理类的对象  
    private Object target;  
      
    //绑定被代理对象  
    public Object bind(Object target){  
        this.target = target;  
        //返回实现了被代理类所实现的所有接口的Object对象，即动态代理，需要强制转型  
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),   
                target.getClass().getInterfaces(), this);  
    }  
    //日志记录方法  
    private void log(String method){  
        System.out.println("进行日志记录，方法为：" + method);  
    }  
    //事物提交方法  
    private void commit(){  
        System.out.println("事物提交");  
    }  
      
    /** 
     * <p>Discription:覆盖InvocationHandler接口中的invoke()方法</p> 
     * @param proxy 需要代理的对象 
     * @param method 真实主体要调用的执行方法 
     * @param args 调用方法时传递的参数 
     * @return 
     * @throws Throwable 
     * @author       : lcma 
     * @update       : 2016年10月9日下午2:46:29 
     */  
    @Override  
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
        //日志记录操作  
        this.log(method.getName());  
        //使用反射中的invoke()对方法进行动态调用  
        Object obj = method.invoke(this.target, args);  
        //过滤出以do开头的方法，该方法对数据库进行修改，进行事物提交操作  
        if(method.getName().matches("do[a-zA-Z0-9]+")){  
            this.commit();  
        }  
        return obj;  
    }  
}  
//测试类  
public class AutoProxy {  
    public static void main(String[] args){  
        //获得代理的实例  
        DaoI dao = (DaoI)new DaoProxy().bind(new DaoImpl());  
        //调用被代理类中的保存方法  
        dao.doSave();  
        System.out.println("--------------分割线-----------------");  
        //获取被代理类中的获取方法  
        dao.getById("123");  
    }  
} 
```
####输出结果：
```java
进行日志记录，方法为：doSave  
执行保存方法【doSave】  
事物提交  
--------------分割线-----------------  
进行日志记录，方法为：getById  
执行根据ID查找对象方法【getById】  
```
动态代理模式可以让我们在不改变原来代码结构的情况下，对原来的“真实方法”进行扩展、增强其功能，并且可以达到控制被代理对象的行为。
动态代理模式运用的知识点就是Java的反射机制，对于上面的代码有些地方我也不是很理解，要想彻底搞懂还有很长的路要走。','2017-07-11 16:29:37','20','0','','1','~~fileDomainName~~//img/201707/1499761695991.jpg','参考：百度百科
JAVA反射机制JAVA反射机制是在运行状态中，对于任意一个类，都能够知道这个类的所有属性和方法；对于任意一个对象，都能够调用它的任意方法和属性；这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
参考：http://blog.csdn.net/mlc1218559742/article/details/52767156代理模式的核心思路就是...','admin','Java反射机制在代理模式中的使用'),
('61','2','###需求
使用google搜索“site:pan.baidu.com”可以搜索出百度网盘共享的内容，想要把这个功能内嵌到自己的网站需要使用“google自定义搜索”。
而使用google搜索首要的就是要先番羽墙，接下来就是简单的在centos7中实现番羽墙。
###实现步骤
1.命令wget https://google.com 无法访问google首页
2.参考：http://www.centoscn.com/CentOS/config/2014/0822/3538.html
需要使用的DNS地址在这里：http://puredns.cn/
2.1使用全新的命令行工具 nmcli 来设置
```
#显示当前网络连接
#nmcli connection show
NAME UUID                                 TYPE           DEVICE
eno1 5fb06bd0-0bb0-7ffb-45f1-d6edd65f3e03 802-3-ethernet eno1

#修改当前网络连接对应的DNS服务器，这里的网络连接可以用名称或者UUID来标识
#nmcli con mod eno1 ipv4.dns "114.114.114.114 8.8.8.8"

#将dns配置生效
#nmcli con up eno1
```
2.2使用传统方法，手工修改 /etc/resolv.conf
```
修改 /etc/NetworkManager/NetworkManager.conf 文件，在main部分添加 “dns=none” 选项：
[main]
plugins=ifcfg-rh
dns=none
NetworkManager重新装载上面修改的配置
# systemctl restart NetworkManager.service
手工修改 /etc/resolv.conf
nameserver 114.114.114.114
nameserver 8.8.8.8
详细参见：
# man NetworkManager.conf
# man nmcli
```','2017-07-17 13:58:27','11','0','','1','~~fileDomainName~~//img/201707/1500271008366.jpg','需求使用google搜索“site:pan.baidu.com”可以搜索出百度网盘共享的内容，想要把这个功能内嵌到自己的网站需要使用“google自定义搜索”。而使用google搜索首要的就是要先番羽墙，接下来就是简单的在centos7中实现番羽墙。
实现步骤1.命令wget https://google.com 无法访问google首页2.参考：http://www.cent...','admin','centos7修改dns实现番羽墙'),
('62','2','参考：http://blog.csdn.net/qq_27376871/article/details/51613066
###一、什么是ASM
　　ASM是一个Java字节码操纵框架，它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件，也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class文件里，这些类文件拥有足够的元数据来解析类中的所有元素：类名称、方法、属性以及 Java 字节码（指令）。ASM从类文件中读入信息后，能够改变类行为，分析类信息，甚至能够根据用户要求生成新类。asm字节码增强技术主要是用来反射的时候提升性能的，如果单纯用jdk的反射调用，性能是非常低下的，而使用字节码增强技术后反射调用的时间已经基本可以与直接调用相当了
　　使用ASM框架需要导入asm的jar包，下载链接：[asm-3.2.jar](http://files.cnblogs.com/liuling/asm-3.2.rar "asm-3.2.jar")。
###二、如何使用ASM
　　ASM框架中的核心类有以下几个：
　　①  ClassReader:该类用来解析编译过的class字节码文件。
　　②  ClassWriter:该类用来重新构建编译后的类，比如说修改类名、属性以及方法，甚至可以生成新的类的字节码文件。
　　③  ClassAdapter:该类也实现了ClassVisitor接口，它将对它的方法调用委托给另一个ClassVisitor对象。
###三、ASM用途
   ASM字节码处理框架是用Java开发的而且使用基于访问者模式生成字节码及驱动类到字节码的转换，通俗的讲，它就是对class文件的CRUD，经过CRUD后的字节码可以转换为类。ASM的解析方式类似于SAX解析XML文件，它综合运用了访问者模式、职责链模式、桥接模式等多种设计模式，相对于其他类似工具如BCEL、SERP、Javassist、CGLIB，它的最大的优势就在于其性能更高，其jar包仅30K。hibernate和spring都使用了cglib代理，而cglib本身就是使用的ASM，可见ASM在各种开源框架都有广泛的应用。
ASM是一个强大的框架，利用它我们可以做到：
---1、获得class文件的详细信息，包括类名、父类名、接口、成员名、方法名、方法参数名、局部变量名、元数据等
---2、对class文件进行动态修改，如增加、删除、修改类方法、在某个方法中添加指令等
CGLIB（动态代理）是对ASM的封装，简化了ASM的操作，降低了ASM的使用门槛，
其中，hibernate的懒加载使用到了asm，spring的AOP也使用到了。你建立一个hibernate映射对象并使用懒加载配置的时候，在内存中生成的对象使用的不再是你实现的那个类了，而是hibernate根据字节码技术已你的类为模板构造的一个新类，证明就是当你获得那个对象输出类名是，不是你自己生成的类名了。spring可能是proxy$xxx，hibernate可能是<你的类名>$xxx$xxx之类的名字。
##AOP 的利器：ASM 3.0 介绍
---随着 AOP（Aspect Oriented Programming）的发展，代码动态生成已然成为 Java 世界中不可或缺的一环。本文将介绍一种小巧轻便的 Java 字节码操控框架 ASM，它能方便地生成和改造 Java 代码。著名的框架，如 Hibernate 和 Spring 在底层都用到了 ASM。比起传统的 Java 字节码操控框架，BCEL 或者 SERP，它具有更符合现代软件模式的编程模型和更迅捷的性能。
---本文主要分为四个部分：首先将 ASM 和其他 Java 类生成方案作对比，然后大致介绍 Java 类文件的组织，最后针对最新的 ASM 3.0，描述其编程框架，并给出一个使用 ASM 进行 AOP 的例子，介绍调整函数内容，生成派生类，以及静态和动态生成类的方法。
##引言
###什么是 ASM ？
ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件，也可以在类被加载入 Java 虚拟机之前动态改变类行为。java class 被存储在严格格式定义的 .class 文件里，这些类文件拥有足够的元数据来解析类中的所有元素：类名称、方法、属性以及 Java 字节码（指令）。ASM 从类文件中读入信息后，能够改变类行为，分析类信息，甚至能够根据用户要求生成新类。
与 BCEL 和 SERL 不同，ASM 提供了更为现代的编程模型。对于 ASM 来说，Java class 被描述为一棵树；使用 “Visitor” 模式遍历整个二进制结构；事件驱动的处理方式使得用户只需要关注于对其编程有意义的部分，而不必了解 Java 类文件格式的所有细节：ASM 框架提供了默认的 “response taker”处理这一切。
###为什么要动态生成 Java 类？
动态生成 Java 类与 AOP 密切相关的。AOP 的初衷在于软件设计世界中存在这么一类代码，零散而又耦合：零散是由于一些公有的功能（诸如著名的 log 例子）分散在所有模块之中；同时改变 log 功能又会影响到所有的模块。出现这样的缺陷，很大程度上是由于传统的 面向对象编程注重以继承关系为代表的“纵向”关系，而对于拥有相同功能或者说方面 （Aspect）的模块之间的“横向”关系不能很好地表达。例如，目前有一个既有的银行管理系统，包括 Bank、Customer、Account、Invoice 等对象，现在要加入一个安全检查模块， 对已有类的所有操作之前都必须进行一次安全检查。
**图 1. ASM – AOP**
![](~~fileDomainName~~//img/201707/1500539758616.jpg)
---然而 Bank、Customer、Account、Invoice 是代表不同的事务，派生自不同的父类，很难在高层上加入关于 Security Checker 的共有功能。对于没有多继承的 Java 来说，更是如此。传统的解决方案是使用 Decorator 模式，它可以在一定程度上改善耦合，而功能仍旧是分散的 —— 每个需要 Security Checker 的类都必须要派生一个 Decorator，每个需要 Security Checker 的方法都要被包装（wrap）。下面我们以Account类为例看一下 Decorator：
首先，我们有一个 SecurityChecker类，其静态方法 checkSecurity执行安全检查功能：
```java
public class SecurityChecker { 
	 public static void checkSecurity() { 
		 System.out.println("SecurityChecker.checkSecurity ..."); 
		 //TODO real security check 
	 } 	
 }
```
另一个是 Account类：
```java
public class Account { 
	 public void operation() { 
		 System.out.println("operation..."); 
		 //TODO real operation 
	 } 
 }
```
若想对 operation加入对 SecurityCheck.checkSecurity()调用，标准的 Decorator 需要先定义一个Account类的接口：
```java
public interface Account { 
	 void operation(); 
 }
```
然后把原来的 Account类定义为一个实现类：
```java
public class AccountImpl extends Account{ 
	 public void operation() { 
		 System.out.println("operation..."); 
		 //TODO real operation 
	 } 
 }
```
定义一个 Account类的 Decorator，并包装 operation方法：
```java
 public class AccountWithSecurityCheck implements Account { 	
	 private  Account account; 
	 public AccountWithSecurityCheck (Account account) { 
		 this.account = account; 
	 } 
	 public void operation() { 
		 SecurityChecker.checkSecurity(); 
		 account.operation(); 
	 } 
 }
```
---在这个简单的例子里，改造一个类的一个方法还好，如果是变动整个模块，Decorator 很快就会演化成另一个噩梦。动态改变 Java 类就是要解决 AOP 的问题，提供一种得到系统支持的可编程的方法，自动化地生成或者增强 Java 代码。这种技术已经广泛应用于最新的 Java 框架内，如 Hibernate，Spring 等。
###为什么选择 ASM ？
---最直接的改造 Java 类的方法莫过于直接改写 class 文件。Java 规范详细说明了 class 文件的格式，直接编辑字节码确实可以改变 Java 类的行为。直到今天，还有一些 Java 高手们使用最原始的工具，如 UltraEdit 这样的编辑器对 class 文件动手术。是的，这是最直接的方法，但是要求使用者对 Java class 文件的格式了熟于心：小心地推算出想改造的函数相对文件首部的偏移量，同时重新计算 class 文件的校验码以通过 Java 虚拟机的安全机制。
---Java 5 中提供的 Instrument 包也可以提供类似的功能：启动时往 Java 虚拟机中挂上一个用户定义的 hook 程序，可以在装入特定类的时候改变特定类的字节码，从而改变该类的行为。但是其缺点也是明显的：
- Instrument 包是在整个虚拟机上挂了一个钩子程序，每次装入一个新类的时候，都必须执行一遍这段程序，即使这个类不需要改变。

- 直接改变字节码事实上类似于直接改写 class 文件，无论是调用 ClassFileTransformer. transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer)，还是Instrument.redefineClasses(ClassDefinition[] definitions)，都必须提供新 Java 类的字节码。也就是说，同直接改写 class 文件一样，使用 Instrument 也必须了解想改造的方法相对类首部的偏移量，才能在适当的位置上插入新的代码。

---尽管 Instrument 可以改造类，但事实上，Instrument 更适用于监控和控制虚拟机的行为。
---一种比较理想且流行的方法是使用 java.lang.ref.proxy。我们仍旧使用上面的例子，给 Account类加上 checkSecurity 功能 :
---首先，Proxy 编程是面向接口的。下面我们会看到，Proxy 并不负责实例化对象，和 Decorator 模式一样，要把 Account定义成一个接口，然后在AccountImpl里实现Account接口，接着实现一个 InvocationHandlerAccount方法被调用的时候，虚拟机都会实际调用这个InvocationHandler的invoke方法：
```java
 class SecurityProxyInvocationHandler implements InvocationHandler { 
	 private Object proxyedObject; 
	 public SecurityProxyInvocationHandler(Object o) { 
		 proxyedObject = o; 
	 } 
		
	 public Object invoke(Object object, Method method, Object[] arguments) 
		 throws Throwable { 			
		 if (object instanceof Account && method.getName().equals("opertaion")) { 
			 SecurityChecker.checkSecurity(); 
		 } 
		 return method.invoke(proxyedObject, arguments); 
	 } 
 }
```
最后，在应用程序中指定 InvocationHandler生成代理对象：
```java
public static void main(String[] args) { 
	 Account account = (Account) Proxy.newProxyInstance( 
		 Account.class.getClassLoader(), 
		 new Class[] { Account.class }, 
		 new SecurityProxyInvocationHandler(new AccountImpl()) 
	 ); 
	 account.function(); 
 }
```
####其不足之处在于：
---Proxy 是面向接口的，所有使用 Proxy 的对象都必须定义一个接口，而且用这些对象的代码也必须是对接口编程的：Proxy 生成的对象是接口一致的而不是对象一致的：例子中Proxy.newProxyInstance生成的是实现Account接口的对象而不是 AccountImpl的子类。这对于软件架构设计，尤其对于既有软件系统是有一定掣肘的。
---Proxy 毕竟是通过反射实现的，必须在效率上付出代价：有实验数据表明，调用反射比一般的函数开销至少要大 10 倍。而且，从程序实现上可以看出，对 proxy class 的所有方法调用都要通过使用反射的 invoke 方法。因此，对于性能关键的应用，使用 proxy class 是需要精心考虑的，以避免反射成为整个应用的瓶颈。

---ASM 能够通过改造既有类，直接生成需要的代码。增强的代码是硬编码在新生成的类文件内部的，没有反射带来性能上的付出。同时，ASM 与 Proxy 编程不同，不需要为增强代码而新定义一个接口，生成的代码可以覆盖原来的类，或者是原始类的子类。它是一个普通的 Java 类而不是 proxy 类，甚至可以在应用程序的类框架中拥有自己的位置，派生自己的子类。
---相比于其他流行的 Java 字节码操纵工具，ASM 更小更快。ASM 具有类似于 BCEL 或者 SERP 的功能，而只有 33k 大小，而后者分别有 350k 和 150k。同时，同样类转换的负载，如果 ASM 是 60% 的话，BCEL 需要 700%，而 SERP 需要 1100% 或者更多。
---ASM 已经被广泛应用于一系列 Java 项目：AspectWerkz、AspectJ、BEA WebLogic、IBM AUS、OracleBerkleyDB、Oracle TopLink、Terracotta、RIFE、EclipseME、Proactive、Speedo、Fractal、EasyBeans、BeanShell、Groovy、Jamaica、CGLIB、dynaop、Cobertura、JDBCPersistence、JiP、SonarJ、Substance L&F、Retrotranslator 等。Hibernate 和 Spring 也通过 cglib，另一个更高层一些的自动代码生成工具使用了 ASM。
###Java 类文件概述
所谓 Java 类文件，就是通常用 javac 编译器产生的 .class 文件。这些文件具有严格定义的格式。为了更好的理解 ASM，首先对 Java 类文件格式作一点简单的介绍。Java 源文件经过 javac 编译器编译之后，将会生成对应的二进制文件（如下图所示）。每个合法的 Java 类文件都具备精确的定义，而正是这种精确的定义，才使得 Java 虚拟机得以正确读取和解释所有的 Java 类文件。
**图 2. ASM – Javac 流程**
![](http://www.ibm.com/developerworks/cn/java/j-lo-asm30/fig002.jpg)
---Java 类文件是 8 位字节的二进制流。数据项按顺序存储在 class 文件中，相邻的项之间没有间隔，这使得 class 文件变得紧凑，减少存储空间。在 Java 类文件中包含了许多大小不同的项，由于每一项的结构都有严格规定，这使得 class 文件能够从头到尾被顺利地解析。下面让我们来看一下 Java 类文件的内部结构，以便对此有个大致的认识。
例如，一个最简单的 Hello World 程序：
```java
public class HelloWorld { 
	 public static void main(String[] args) { 
		 System.out.println("Hello world"); 
	 } 
 }
```
经过 javac 编译后，得到的类文件大致是：
###图 3. ASM – Java 类文件
![](http://www.ibm.com/developerworks/cn/java/j-lo-asm30/fig003.jpg)
从上图中可以看到，一个 Java 类文件大致可以归为 10 个项：
- Magic：该项存放了一个 Java 类文件的魔数（magic number）和版本信息。一个 Java 类文件的前 4 个字节被称为它的魔数。每个正确的 Java 类文件都是以 0xCAFEBABE 开头的，这样保证了 Java 虚拟机能很轻松的分辨出 Java 文件和非 Java 文件。

- Version：该项存放了 Java 类文件的版本信息，它对于一个 Java 文件具有重要的意义。因为 Java 技术一直在发展，所以类文件的格式也处在不断变化之中。类文件的版本信息让虚拟机知道如何去读取并处理该类文件。

- Constant Pool：该项存放了类中各种文字字符串、类名、方法名和接口名称、final 变量以及对外部类的引用信息等常量。虚拟机必须为每一个被装载的类维护一个常量池，常量池中存储了相应类型所用到的所有类型、字段和方法的符号引用，因此它在 Java 的动态链接中起到了核心的作用。常量池的大小平均占到了整个类大小的 60% 左右。

- Access_flag：该项指明了该文件中定义的是类还是接口（一个 class 文件中只能有一个类或接口），同时还指名了类或接口的访问标志，如 public，private, abstract 等信息。

- This Class：指向表示该类全限定名称的字符串常量的指针。

- Super Class：指向表示父类全限定名称的字符串常量的指针。

- Interfaces：一个指针数组，存放了该类或父类实现的所有接口名称的字符串常量的指针。以上三项所指向的常量，特别是前两项，在我们用 ASM 从已有类派生新类时一般需要修改：将类名称改为子类名称；将父类改为派生前的类名称；如果有必要，增加新的实现接口。

- Fields：该项对类或接口中声明的字段进行了细致的描述。需要注意的是，fields 列表中仅列出了本类或接口中的字段，并不包括从超类和父接口继承而来的字段。

- Methods：该项对类或接口中声明的方法进行了细致的描述。例如方法的名称、参数和返回值类型等。需要注意的是，methods 列表里仅存放了本类或本接口中的方法，并不包括从超类和父接口继承而来的方法。使用 ASM 进行 AOP 编程，通常是通过调整 Method 中的指令来实现的。

- Class attributes：该项存放了在该文件中类或接口所定义的属性的基本信息。

---事实上，使用 ASM 动态生成类，不需要像早年的 class hacker 一样，熟知 class 文件的每一段，以及它们的功能、长度、偏移量以及编码方式。ASM 会给我们照顾好这一切的，我们只要告诉 ASM 要改动什么就可以了 —— 当然，我们首先得知道要改什么：对类文件格式了解的越多，我们就能更好地使用 ASM 这个利器。
###ASM 3.0 编程框架
---ASM 通过树这种数据结构来表示复杂的字节码结构，并利用 Push 模型来对树进行遍历，在遍历过程中对字节码进行修改。所谓的 Push 模型类似于简单的 Visitor 设计模式，因为需要处理字节码结构是固定的，所以不需要专门抽象出一种 Vistable 接口，而只需要提供 Visitor 接口。所谓 Visitor 模式和 Iterator 模式有点类似，它们都被用来遍历一些复杂的数据结构。Visitor 相当于用户派出的代表，深入到算法内部，由算法安排访问行程。Visitor 代表可以更换，但对算法流程无法干涉，因此是被动的，这也是它和 Iterator 模式由用户主动调遣算法方式的最大的区别。
---在 ASM 中，提供了一个 ClassReader类，这个类可以直接由字节数组或由 class 文件间接的获得字节码数据，它能正确的分析字节码，构建出抽象的树在内存中表示字节码。它会调用accept方法，这个方法接受一个实现了ClassVisitor接口的对象实例作为参数，然后依次调用 ClassVisitor接口的各个方法。字节码空间上的偏移被转换成 visit 事件时间上调用的先后，所谓 visit 事件是指对各种不同 visit 函数的调用，ClassReader知道如何调用各种 visit 函数。在这个过程中用户无法对操作进行干涉，所以遍历的算法是确定的，用户可以做的是提供不同的 Visitor 来对字节码树进行不同的修改。ClassVisitor会产生一些子过程，比如visitMethod会返回一个实现MethordVisitor接口的实例，visitField会返回一个实现FieldVisitor接口的实例，完成子过程后控制返回到父过程，继续访问下一节点。因此对于ClassReader来说，其内部顺序访问是有一定要求的。实际上用户还可以不通过ClassReader类，自行手工控制这个流程，只要按照一定的顺序，各个 visit 事件被先后正确的调用，最后就能生成可以被正确加载的字节码。当然获得更大灵活性的同时也加大了调整字节码的复杂度。
---各个 ClassVisitor通过职责链 （Chain-of-responsibility） 模式，可以非常简单的封装对字节码的各种修改，而无须关注字节码的字节偏移，因为这些实现细节对于用户都被隐藏了，用户要做的只是覆写相应的 visit 函数。
---ClassAdaptor类实现了 ClassVisitor接口所定义的所有函数，当新建一个 ClassAdaptor对象的时候，需要传入一个实现了 ClassVisitor接口的对象，作为职责链中的下一个访问者 （Visitor），这些函数的默认实现就是简单的把调用委派给这个对象，然后依次传递下去形成职责链。当用户需要对字节码进行调整时，只需从ClassAdaptor类派生出一个子类，覆写需要修改的方法，完成相应功能后再把调用传递下去。这样，用户无需考虑字节偏移，就可以很方便的控制字节码。
---每个 ClassAdaptor类的派生类可以仅封装单一功能，比如删除某函数、修改字段可见性等等，然后再加入到职责链中，这样耦合更小，重用的概率也更大，但代价是产生很多小对象，而且职责链的层次太长的话也会加大系统调用的开销，用户需要在低耦合和高效率之间作出权衡。用户可以通过控制职责链中 visit 事件的过程，对类文件进行如下操作：
---1.删除类的字段、方法、指令：只需在职责链传递过程中中断委派，不访问相应的 visit 方法即可，比如删除方法时只需直接返回 null，而不是返回由visitMethod方法返回的MethodVisitor对象。
```java
class DelLoginClassAdapter extends ClassAdapter { 
	 public DelLoginClassAdapter(ClassVisitor cv) { 
		 super(cv); 
	 } 

	 public MethodVisitor visitMethod(final int access, final String name, 
		 final String desc, final String signature, final String[] exceptions) { 
		 if (name.equals("login")) { 
			 return null; 
		 } 
		 return cv.visitMethod(access, name, desc, signature, exceptions); 
	 } 
 }
```
---2.修改类、字段、方法的名字或修饰符：在职责链传递过程中替换调用参数。
```java
 class AccessClassAdapter extends ClassAdapter { 
	 public AccessClassAdapter(ClassVisitor cv) { 
		 super(cv); 
	 } 

	 public FieldVisitor visitField(final int access, final String name, 
        final String desc, final String signature, final Object value) { 
        int privateAccess = Opcodes.ACC_PRIVATE; 
        return cv.visitField(privateAccess, name, desc, signature, value); 
    } 
 }
```
---3.增加新的类、方法、字段
---ASM 的最终的目的是生成可以被正常装载的 class 文件，因此其框架结构为客户提供了一个生成字节码的工具类 —— ClassWriter。它实现了ClassVisitor接口，而且含有一个toByteArray()函数，返回生成的字节码的字节流，将字节流写回文件即可生产调整后的 class 文件。一般它都作为职责链的终点，把所有 visit 事件的先后调用（时间上的先后），最终转换成字节码的位置的调整（空间上的前后），如下例：
```java
 ClassWriter  classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS); 
 ClassAdaptor delLoginClassAdaptor = new DelLoginClassAdapter(classWriter); 
 ClassAdaptor accessClassAdaptor = new AccessClassAdaptor(delLoginClassAdaptor); 
	
 ClassReader classReader = new ClassReader(strFileName); 
 classReader.accept(classAdapter, ClassReader.SKIP_DEBUG);
```
综上所述，ASM 的时序图如下：
**图 4. ASM – 时序图**
![](http://www.ibm.com/developerworks/cn/java/j-lo-asm30/fig004.jpg)
###使用 ASM3.0 进行 AOP 编程
---我们还是用上面的例子，给 Account类加上 security check 的功能。与 proxy 编程不同，ASM 不需要将 Account声明成接口，Account可以仍旧是一个实现类。ASM 将直接在 Account类上动手术，给Account类的operation方法首部加上对 SecurityChecker.checkSecurity的调用。
---首先，我们将从 ClassAdapter继承一个类。ClassAdapter是 ASM 框架提供的一个默认类，负责沟通ClassReader和ClassWriter。如果想要改变 ClassReader处读入的类，然后从ClassWriter处输出，可以重写相应的ClassAdapter函数。这里，为了改变 Account类的operation 方法，我们将重写visitMethdod方法。
```java
class AddSecurityCheckClassAdapter extends ClassAdapter {

    public AddSecurityCheckClassAdapter(ClassVisitor cv) {
        //Responsechain 的下一个 ClassVisitor，这里我们将传入 ClassWriter，
        // 负责改写后代码的输出
        super(cv); 
    } 
    
    // 重写 visitMethod，访问到 "operation" 方法时，
    // 给出自定义 MethodVisitor，实际改写方法内容
    public MethodVisitor visitMethod(final int access, final String name, 
        final String desc, final String signature, final String[] exceptions) { 
        MethodVisitor mv = cv.visitMethod(access, name, desc, signature,exceptions);
        MethodVisitor wrappedMv = mv; 
        if (mv != null) { 
            // 对于 "operation" 方法
            if (name.equals("operation")) { 
                // 使用自定义 MethodVisitor，实际改写方法内容
                wrappedMv = new AddSecurityCheckMethodAdapter(mv); 
            } 
        } 
        return wrappedMv; 
    } 
}
```
---下一步就是定义一个继承自 MethodAdapter的 AddSecurityCheckMethodAdapter，在“operation”方法首部插入对SecurityChecker.checkSecurity()的调用。
```java
class AddSecurityCheckMethodAdapter extends MethodAdapter { 
	 public AddSecurityCheckMethodAdapter(MethodVisitor mv) { 
		 super(mv); 
	 } 

	 public void visitCode() { 
		 visitMethodInsn(Opcodes.INVOKESTATIC, "SecurityChecker", 
			"checkSecurity", "()V"); 
	 } 
 }
```
---其中，ClassReader读到每个方法的首部时调用 visitCode()，在这个重写方法里，我们用 visitMethodInsn(Opcodes.INVOKESTATIC, "SecurityChecker","checkSecurity", "()V");插入了安全检查功能。
---最后，我们将集成上面定义的 ClassAdapter，ClassReader和 ClassWriter产生修改后的Account类文件 :
```java
import java.io.File; 
import java.io.FileOutputStream; 
import org.objectweb.asm.*; 
    
 public class Generator{ 
	 public static void main() throws Exception { 
		 ClassReader cr = new ClassReader("Account"); 
		 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); 
		 ClassAdapter classAdapter = new AddSecurityCheckClassAdapter(cw); 
		 cr.accept(classAdapter, ClassReader.SKIP_DEBUG); 
		 byte[] data = cw.toByteArray(); 
		 File file = new File("Account.class"); 
		 FileOutputStream fout = new FileOutputStream(file); 
		 fout.write(data); 
		 fout.close(); 
	 } 
 }
```
---执行完这段程序后，我们会得到一个新的 Account.class 文件，如果我们使用下面代码：
```java
public class Main { 
	 public static void main(String[] args) { 
		 Account account = new Account(); 
		 account.operation(); 
	 } 
 }
```
---使用这个 Account，我们会得到下面的输出：

	 SecurityChecker.checkSecurity ... 
	 operation...

---也就是说，在 Account原来的 operation内容执行之前，进行了 SecurityChecker.checkSecurity()检查。
###将动态生成类改造成原始类 Account 的子类
---上面给出的例子是直接改造 Account类本身的，从此 Account类的 operation方法必须进行 checkSecurity 检查。但事实上，我们有时仍希望保留原来的Account类，因此把生成类定义为原始类的子类是更符合 AOP 原则的做法。下面介绍如何将改造后的类定义为Account的子类Account$EnhancedByASM。其中主要有两项工作 :
- 改变 Class Description, 将其命名为 Account$EnhancedByASM，将其父类指定为 Account。
- 改变构造函数，将其中对父类构造函数的调用转换为对 Account构造函数的调用。

---在 AddSecurityCheckClassAdapter类中，将重写 visit方法：

```java
 public void visit(final int version, final int access, final String name, 
		 final String signature, final String superName, 
		 final String[] interfaces) { 
	 String enhancedName = name + "$EnhancedByASM";  // 改变类命名
	 enhancedSuperName = name; // 改变父类，这里是”Account”
	 super.visit(version, access, enhancedName, signature, 
	 enhancedSuperName, interfaces); 
 }
```
---改进 visitMethod方法，增加对构造函数的处理：
```java
public MethodVisitor visitMethod(final int access, final String name, 
	 final String desc, final String signature, final String[] exceptions) { 
	 MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); 
	 MethodVisitor wrappedMv = mv; 
	 if (mv != null) { 
		 if (name.equals("operation")) { 
			 wrappedMv = new AddSecurityCheckMethodAdapter(mv); 
		 } else if (name.equals("<init>")) { 
			 wrappedMv = new ChangeToChildConstructorMethodAdapter(mv, 
				 enhancedSuperName); 
		 } 
	 } 
	 return wrappedMv; 
 }
```
---这里 ChangeToChildConstructorMethodAdapter将负责把 Account的构造函数改造成其子类Account$EnhancedByASM的构造函数：
```java
class ChangeToChildConstructorMethodAdapter extends MethodAdapter { 
	 private String superClassName; 

	 public ChangeToChildConstructorMethodAdapter(MethodVisitor mv, 
		 String superClassName) { 
		 super(mv); 
		 this.superClassName = superClassName; 
	 } 

	 public void visitMethodInsn(int opcode, String owner, String name, 
		 String desc) { 
		 // 调用父类的构造函数时
		 if (opcode == Opcodes.INVOKESPECIAL && name.equals("<init>")) { 
			 owner = superClassName; 
		 } 
		 super.visitMethodInsn(opcode, owner, name, desc);// 改写父类为 superClassName 
	 } 
 }
```
---最后演示一下如何在运行时产生并装入产生的 Account$EnhancedByASM。 我们定义一个 Util 类，作为一个类工厂负责产生有安全检查的Account类：
```java
public class SecureAccountGenerator { 

    private static AccountGeneratorClassLoader classLoader = 
        new AccountGeneratorClassLoade(); 
    
    private static Class secureAccountClass; 
    
    public Account generateSecureAccount() throws ClassFormatError, 
        InstantiationException, IllegalAccessException { 
        if (null == secureAccountClass) {            
            ClassReader cr = new ClassReader("Account"); 
            ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); 
            ClassAdapter classAdapter = new AddSecurityCheckClassAdapter(cw);
            cr.accept(classAdapter, ClassReader.SKIP_DEBUG); 
            byte[] data = cw.toByteArray(); 
            secureAccountClass = classLoader.defineClassFromClassFile( 
               "Account$EnhancedByASM",data); 
        } 
        return (Account) secureAccountClass.newInstance(); 
    } 
    
    private static class AccountGeneratorClassLoader extends ClassLoader {
        public Class defineClassFromClassFile(String className, 
            byte[] classFile) throws ClassFormatError { 
            return defineClass("Account$EnhancedByASM", classFile, 0, 
	        classFile.length());
        } 
    } 
}
```
---静态方法 SecureAccountGenerator.generateSecureAccount()在运行时动态生成一个加上了安全检查的Account子类。著名的 Hibernate 和 Spring 框架，就是使用这种技术实现了 AOP 的“无损注入”。
##小结
---最后，我们比较一下 ASM 和其他实现 AOP 的底层技术：
**表 1. AOP 底层技术比较**



|AOP 底层技术	|功能	|性能	|面向接口编程	|编程难度|
| ------------ | ------------ | ------------ | ------------ | ------------ | ------------ |
|直接改写 class 文件	|完全控制类	|无明显性能代价	|不要求	|高，要求对 class 文件结构和 Java 字节码有深刻了解|
|JDK Instrument|	完全控制类	|无论是否改写，每个类装入时都要执行 hook 程序	|不要求	|高，要求对 class 文件结构和 Java 字节码有深刻了解|
|JDK Proxy	|只能改写 method	|反射引入性能代价	|要求	|低|
|ASM	|几乎能完全控制类	|无明显性能代价	|不要求	|中，能操纵需要改写部分的 Java 字节码|','2017-07-20 16:24:59','22','0','','1','~~fileDomainName~~//img/201707/1500539076899.jpg','参考：http://blog.csdn.net/qq_27376871/article/details/51613066
一、什么是ASM　　ASM是一个Java字节码操纵框架，它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件，也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class...','admin','关于java字节码框架ASM的学习'),
('63','2','Tampermonkey浏览器脚本增强插件
###关于Tampermonkey
Tampermonkey 是一款免费的浏览器扩展和最为流行的用户脚本管理器，它适用于 Chrome, Microsoft Edge, Safari, Opera Next, 和 Firefox。 

虽然有些受支持的浏览器拥有原生的用户脚本支持，但 Tampermonkey 将在您的用户脚本管理方面提供更多的便利。 它提供了诸如便捷脚本安装、自动更新检查、标签中的脚本运行状况速览、内置的编辑器等众多功能， 同时Tampermonkey还有可能正常运行原本并不兼容的脚本。 

Tampermonkey 可用于 Google Chrome, Microsoft Edge, Opera, Chromium,及其众多衍生产品如 CoolNovo 和 Rockmelt ,还有Firefox和一些安卓浏览器。 它可以很快的安装好，来试一试吧！
官网：http://tampermonkey.net/

###Tampermonkey有很多被人写好的插件库

其中一个：https://greasyfork.org/zh-CN

##使用

###第一步：安装一个用户脚本管理器

Tampermonkey manage
Chrome 上的 Tampermonkey
要使用用户脚本，您首先需要安装一个用户脚本管理器。根据您使用的浏览器不同，可用的用户脚本管理器也有所不同。

- Chrome：[Tampermonkey](https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo "Tampermonkey") 或 [Violent monkey](https://chrome.google.com/webstore/detail/violent-monkey/jinjaccalgkegednnccohejagnlnfdag "Violent monkey")
- Firefox：[Greasemonkey](https://addons.mozilla.org/firefox/addon/greasemonkey/ "Greasemonkey")、[Tampermonkey](https://addons.mozilla.org/firefox/addon/tampermonkey/ "Tampermonkey")
- 或 [Violentmonkey](https://addons.mozilla.org/firefox/addon/violentmonkey/ "Violentmonkey")
- Safari：[Tampermonkey](http://tampermonkey.net/?browser=safari "Tampermonkey")
- Microsoft Edge：[Tampermonkey](https://www.microsoft.com/store/p/tampermonkey/9nblggh5162s "Tampermonkey")
- Opera：[Tampermonkey](https://addons.opera.com/extensions/details/tampermonkey-beta/ "Tampermonkey")
- 或 [Violentmonkey](https://addons.opera.com/extensions/details/violent-monkey/ "Violentmonkey")
- Maxthon：[Violentmonkey](http://extension.maxthon.com/detail/index.php?view_id=1680 "Violentmonkey")
- Dolphin：[Tampermonkey](https://play.google.com/store/apps/details?id=net.tampermonkey.dolphin "Tampermonkey")
- UC：[Tampermonkey](https://play.google.com/store/apps/details?id=net.tampermonkey.uc "Tampermonkey")
- Qupzilla：（不需要额外软件）

###第二步：安装一个用户脚本

- Install button example
- 用户脚本的安装按钮
- [浏览此网站](https://greasyfork.org/zh-CN "浏览此网站") 查找您想尝试的用户脚本。最流行的用户脚本有：

- AC-baidu： 优化百度、搜狗、谷歌搜索结果之重定向去除+去广告+favicon - 1.繞過百度、搜狗搜索結果中的自己的跳轉鏈接，直接訪問原始網頁-反正都能看懂 2.去除百度的多余广告3.添加Favicon显示
- VIP视频破解 - 解析并破解各大视频站的VIP权限
- 网页限制解除 - 通杀大部分网站，可以解除禁止复制、剪切、选择文本、右键菜单的限制。
- 解决百度云大文件下载限制 - 一行代码，解决百度云大文件下载限制
- 购物党比价工具 - 浏览商品页面时，自动比较同款商品在淘宝/京东/亚马逊/当当/苏宁/等百家商城的最低价，提供价格历史、口碑评分等查询。

- 在您找到想要的用户脚本后，点击用户脚本页面上绿色的安装按钮，您的用户脚本管理器将询问您是否安装。

###第三步：使用用户脚本

- 转至用户脚本适用的网站。它应该已自动启动和生效。在试用用户脚本后，您可以返回用户脚本页面，给用户脚本的作者留下反馈。','2017-07-21 14:24:55','1128','0','','1','~~fileDomainName~~//img/201707/1500699613161.jpg','Tampermonkey浏览器脚本增强插件
关于TampermonkeyTampermonkey 是一款免费的浏览器扩展和最为流行的用户脚本管理器，它适用于 Chrome, Microsoft Edge, Safari, Opera Next, 和 Firefox。 
虽然有些受支持的浏览器拥有原生的用户脚本支持，但 Tampermonkey 将在您的用户脚本管理方面提供更多的...','admin','Tampermonkey浏览器脚本增强插件');
DROP TABLE IF EXISTS  `sys_user`;
CREATE TABLE `sys_user` (
  `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `userName` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '用户名',
  `accountName` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '账号',
  `password` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '密码',
  `credentialsSalt` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '加密盐',
  `description` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '描述',
  `status` varchar(3) COLLATE utf8_unicode_ci DEFAULT '0' COMMENT '状态0:正常 1:禁用 ',
  `createTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `deletestatus` int(1) DEFAULT '0' COMMENT '逻辑删除状态0:存在1:删除',
  `isadmin` int(1) DEFAULT '0' COMMENT '是否为管理员 0否1是',
  PRIMARY KEY (`id`),
  UNIQUE KEY `accountName` (`accountName`)
) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

insert into `sys_user`(`id`,`userName`,`accountName`,`password`,`credentialsSalt`,`description`,`status`,`createTime`,`deletestatus`,`isadmin`) values
('1','超级管理员','sysadmin','1111111','3125728978385538515','超级管理员','0','2017-03-21 13:09:58','0','0'),
('2','坏银','admin','1406958322','-1517570141877050956','坏银的备注','0','2017-03-21 14:52:51','0','0');
DROP TABLE IF EXISTS  `sys_dictionary_type`;
CREATE TABLE `sys_dictionary_type` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `typecode` varchar(255) DEFAULT NULL COMMENT '类型编码',
  `typename` varchar(255) DEFAULT NULL COMMENT '类型名称',
  `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

insert into `sys_dictionary_type`(`id`,`typecode`,`typename`,`remark`) values
('1','qiniu','文件存储-七牛','文件存储-七牛'),
('2','local','文件存储-本地','文件存储-本地'),
('3','qcloud','文件存储-腾讯云','文件存储-腾讯云'),
('4','baseInfo','基础信息配置','基础信息配置');
DROP TABLE IF EXISTS  `program`;
CREATE TABLE `program` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL COMMENT '显示名称',
  `url` varchar(200) DEFAULT NULL COMMENT 'url链接',
  `ordernum` int(11) DEFAULT NULL COMMENT '排序序号',
  `status` int(11) DEFAULT NULL COMMENT '状态',
  `remark` varchar(500) DEFAULT NULL COMMENT '描述',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS  `sys_res_role`;
CREATE TABLE `sys_res_role` (
  `resId` int(11) NOT NULL COMMENT '资源id',
  `roleId` int(11) NOT NULL COMMENT '角色id',
  PRIMARY KEY (`roleId`,`resId`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

insert into `sys_res_role`(`resId`,`roleId`) values
('1','1'),
('2','1');
DROP TABLE IF EXISTS  `comment`;
CREATE TABLE `comment` (
  `rootid` int(11) NOT NULL COMMENT '根id',
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `content` longtext,
  `parentid` int(11) DEFAULT NULL COMMENT '父id',
  `articleid` int(11) DEFAULT NULL COMMENT '文章id',
  `createtime` datetime DEFAULT NULL COMMENT '评论日期',
  `ip` varchar(100) DEFAULT NULL,
  `staus` int(11) DEFAULT NULL COMMENT '状态',
  `browser` varchar(50) DEFAULT NULL COMMENT '浏览器版本',
  `os` varchar(50) DEFAULT NULL COMMENT '操作系统',
  `email` varchar(200) DEFAULT NULL COMMENT '邮箱地址',
  `name` varchar(20) DEFAULT NULL COMMENT '姓名',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS  `article_category`;
CREATE TABLE `article_category` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `articleid` int(11) DEFAULT NULL COMMENT '文章id',
  `categoryid` int(11) DEFAULT NULL COMMENT '类别id',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=179 DEFAULT CHARSET=utf8;

insert into `article_category`(`id`,`articleid`,`categoryid`) values
('147','41','4'),
('146','42','4'),
('145','43','5'),
('166','44','6'),
('143','45','6'),
('142','46','6'),
('141','48','6'),
('140','49','6'),
('139','50','7'),
('138','51','7'),
('137','52','7'),
('150','53','7'),
('153','54','7'),
('162','55','6'),
('158','56','4'),
('163','57','8'),
('164','58','8'),
('165','59','8'),
('176','60','7'),
('171','61','6'),
('173','62','7'),
('175','63','5'),
('178','64','4');
SET FOREIGN_KEY_CHECKS = 1;

